Cum rezolv și eu asta, că orice linie aș modifica, mi se crează bug:
Ori nu-mi merge skill bar-ul,
Ori nu-mi merg unele pătrățele din inventar,
Ori când apăs pe shop, se deschide, dau reload p și după ajung la login,
Ori ajung la login și primesc game.core
*Resursă folosită (sistem/funcție/modificare):
personala
Sursă game - C++17
Sursă binary - vs22
Client - varză - eter
----------------------
*Syserr:
----------------------
input.cpp:
#include "stdafx.h"
#include <sstream>
#include "desc.h"
#include "desc_manager.h"
#include "char.h"
#include "buffer_manager.h"
#include "config.h"
#include "profiler.h"
#include "p2p.h"
#include "log.h"
#include "db.h"
#include "questmanager.h"
#include "login_sim.h"
#include "fishing.h"
#include "TrafficProfiler.h"
#include "priv_manager.h"
#include "castle.h"
#include "dev_log.h"
#ifndef __WIN32__
#include "limit_time.h"
#endif
extern time_t get_global_time();
extern bool g_bNoPasspod;
bool IsEmptyAdminPage()
{
return g_stAdminPageIP.empty();
}
bool IsAdminPage(const char * ip)
{
for (size_t n = 0; n < g_stAdminPageIP.size(); ++n)
{
if (g_stAdminPageIP[n] == ip)
return 1;
}
return 0;
}
void ClearAdminPages()
{
for (size_t n = 0; n < g_stAdminPageIP.size(); ++n)
g_stAdminPageIP[n].clear();
g_stAdminPageIP.clear();
}
CInputProcessor::CInputProcessor() : m_pPacketInfo(NULL), m_iBufferLeft(0)
{
if (!m_pPacketInfo)
BindPacketInfo(&m_packetInfoCG);
}
void CInputProcessor::BindPacketInfo(CPacketInfo * pPacketInfo)
{
m_pPacketInfo = pPacketInfo;
}
bool CInputProcessor::Process(LPDESC lpDesc, const void * c_pvOrig, int iBytes, int & r_iBytesProceed)
{
const char * c_pData = (const char *) c_pvOrig;
BYTE bLastHeader = 0;
int iLastPacketLen = 0;
int iPacketLen;
if (!m_pPacketInfo)
{
sys_err("No packet info has been binded to");
return true;
}
for (m_iBufferLeft = iBytes; m_iBufferLeft > 0;)
{
BYTE bHeader = (BYTE) *(c_pData);
const char * c_pszName;
if (bHeader == 0) // 암호화 처리가 있으므로 0번 헤더는 스킵한다.
iPacketLen = 1;
else if (!m_pPacketInfo->Get(bHeader, &iPacketLen, &c_pszName))
{
sys_err("UNKNOWN HEADER: %d, LAST HEADER: %d(%d), REMAIN BYTES: %d, fd: %d",
bHeader, bLastHeader, iLastPacketLen, m_iBufferLeft, lpDesc->GetSocket());
//printdata((BYTE *) c_pvOrig, m_iBufferLeft);
lpDesc->SetPhase(PHASE_CLOSE);
return true;
}
if (m_iBufferLeft < iPacketLen)
return true;
if (bHeader)
{
if (test_server && bHeader != HEADER_CG_MOVE)
sys_log(0, "Packet Analyze [Header %d][bufferLeft %d] ", bHeader, m_iBufferLeft);
m_pPacketInfo->Start();
int iExtraPacketSize = Analyze(lpDesc, bHeader, c_pData);
if (iExtraPacketSize < 0)
return true;
iPacketLen += iExtraPacketSize;
lpDesc->Log("%s %d", c_pszName, iPacketLen);
m_pPacketInfo->End();
}
// TRAFFIC_PROFILER
if (g_bTrafficProfileOn)
TrafficProfiler::instance().Report(TrafficProfiler::IODIR_INPUT, bHeader, iPacketLen);
// END_OF_TRAFFIC_PROFILER
if (bHeader == HEADER_CG_PONG)
sys_log(0, "PONG! %u %u", m_pPacketInfo->IsSequence(bHeader), *(BYTE *) (c_pData + iPacketLen - sizeof(BYTE)));
if (m_pPacketInfo->IsSequence(bHeader))
{
BYTE bSeq = lpDesc->GetSequence();
BYTE bSeqReceived = *(BYTE *) (c_pData + iPacketLen - sizeof(BYTE));
if (bSeq != bSeqReceived)
{
sys_err("SEQUENCE %x mismatch 0x%x != 0x%x header %u", get_pointer(lpDesc), bSeq, bSeqReceived, bHeader);
LPCHARACTER ch = lpDesc->GetCharacter();
char buf[1024];
int offset, len;
offset = snprintf(buf, sizeof(buf), "SEQUENCE_LOG [%s]-------------\n", ch ? ch->GetName() : "UNKNOWN");
if (offset < 0 || offset >= (int) sizeof(buf))
offset = sizeof(buf) - 1;
for (size_t i = 0; i < lpDesc->m_seq_vector.size(); ++i)
{
len = snprintf(buf + offset, sizeof(buf) - offset, "\t[%03d : 0x%x]\n",
lpDesc->m_seq_vector[i].hdr,
lpDesc->m_seq_vector[i].seq);
if (len < 0 || len >= (int) sizeof(buf) - offset)
offset += (sizeof(buf) - offset) - 1;
else
offset += len;
}
snprintf(buf + offset, sizeof(buf) - offset, "\t[%03d : 0x%x]\n", bHeader, bSeq);
sys_err("%s", buf);
lpDesc->SetPhase(PHASE_CLOSE);
return true;
}
else
{
lpDesc->push_seq(bHeader, bSeq);
lpDesc->SetNextSequence();
//sys_err("SEQUENCE %x match %u next %u header %u", lpDesc, bSeq, lpDesc->GetSequence(), bHeader);
}
}
c_pData += iPacketLen;
m_iBufferLeft -= iPacketLen;
r_iBytesProceed += iPacketLen;
iLastPacketLen = iPacketLen;
bLastHeader = bHeader;
if (GetType() != lpDesc->GetInputProcessor()->GetType())
return false;
}
return true;
}
void CInputProcessor::Pong(LPDESC d)
{
d->SetPong(true);
extern bool Metin2Server_IsInvalid();
#ifdef ENABLE_LIMIT_TIME
if (Metin2Server_IsInvalid())
{
extern bool g_bShutdown;
g_bShutdown = true;
ClearAdminPages();
}
#endif
}
void CInputProcessor::Handshake(LPDESC d, const char * c_pData)
{
TPacketCGHandshake * p = (TPacketCGHandshake *) c_pData;
if (d->GetHandshake() != p->dwHandshake)
{
sys_err("Invalid Handshake on %d", d->GetSocket());
d->SetPhase(PHASE_CLOSE);
}
else
{
if (d->IsPhase(PHASE_HANDSHAKE))
{
if (d->HandshakeProcess(p->dwTime, p->lDelta, false))
{
#ifdef _IMPROVED_PACKET_ENCRYPTION_
d->SendKeyAgreement();
#else
if (g_bAuthServer)
d->SetPhase(PHASE_AUTH);
else
d->SetPhase(PHASE_LOGIN);
#endif // #ifdef _IMPROVED_PACKET_ENCRYPTION_
}
}
else
d->HandshakeProcess(p->dwTime, p->lDelta, true);
}
}
void CInputProcessor::Version(LPCHARACTER ch, const char* c_pData)
{
if (!ch)
{
return;
}
TPacketCGClientVersion * p = (TPacketCGClientVersion *) c_pData;
// If the file name is not metin2client.exe and the GM level is not equal with GM_IMPLEMENTOR kick the player
if (strcmp(p->filename, "Trot-OSBD.exe") && ch->GetGMLevel() != GM_IMPLEMENTOR)
{
// immediately close the connection with the player
sys_err("%s[%d] has been disconnected: %s", ch->GetName(), ch->GetPlayerID(), p->filename);
ch->GetDesc()->SetPhase(PHASE_CLOSE);
return;
}
sys_log(0, "VERSION: %s %s %s", ch->GetName(), p->timestamp, p->filename);
ch->GetDesc()->SetClientVersion(p->timestamp);
}
void LoginFailure(LPDESC d, const char * c_pszStatus)
{
if (!d)
return;
TPacketGCLoginFailure failurePacket;
failurePacket.header = HEADER_GC_LOGIN_FAILURE;
strlcpy(failurePacket.szStatus, c_pszStatus, sizeof(failurePacket.szStatus));
d->Packet(&failurePacket, sizeof(failurePacket));
}
CInputHandshake::CInputHandshake()
{
CPacketInfoCG * pkPacketInfo = M2_NEW CPacketInfoCG;
pkPacketInfo->SetSequence(HEADER_CG_PONG, false);
m_pMainPacketInfo = m_pPacketInfo;
BindPacketInfo(pkPacketInfo);
}
CInputHandshake::~CInputHandshake()
{
if( NULL != m_pPacketInfo )
{
M2_DELETE(m_pPacketInfo);
m_pPacketInfo = NULL;
}
}
std::map<DWORD, CLoginSim *> g_sim;
std::map<DWORD, CLoginSim *> g_simByPID;
std::vector<TPlayerTable> g_vec_save;
// BLOCK_CHAT
ACMD(do_block_chat);
// END_OF_BLOCK_CHAT
int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
{
if (bHeader == 10) // 엔터는 무시
return 0;
if (bHeader == HEADER_CG_TEXT)
{
++c_pData;
const char * c_pSep;
if (!(c_pSep = strchr(c_pData, '\n'))) // \n을 찾는다.
return -1;
if (*(c_pSep - 1) == '\r')
--c_pSep;
std::string stResult;
std::string stBuf;
stBuf.assign(c_pData, 0, c_pSep - c_pData);
sys_log(0, "SOCKET_CMD: FROM(%s) CMD(%s)", d->GetHostName(), stBuf.c_str());
if (!stBuf.compare("IS_SERVER_UP"))
{
if (g_bNoMoreClient)
stResult = "NO";
else
stResult = "YES";
}
else if (!stBuf.compare("IS_PASSPOD_UP"))
{
if (g_bNoPasspod)
stResult = "NO";
else
stResult = "YES";
}
//else if (!stBuf.compare("A6969ND41545654D4747488Y"))
else if (stBuf == g_stAdminPagePassword)
{
if (!IsEmptyAdminPage())
{
if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr)))
{
char szTmp[64];
snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr));
stResult += szTmp;
}
else
{
d->SetAdminMode();
stResult = "UNKNOWN";
}
}
else
{
d->SetAdminMode();
stResult = "UNKNOWN";
}
}
else if (!stBuf.compare("USER_COUNT"))
{
char szTmp[64];
if (!IsEmptyAdminPage())
{
if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr)))
{
snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr));
}
else
{
int iTotal;
int * paiEmpireUserCount;
int iLocal;
DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal);
snprintf(szTmp, sizeof(szTmp), "%d %d %d %d %d", iTotal, paiEmpireUserCount[1], paiEmpireUserCount[2], paiEmpireUserCount[3], iLocal);
}
}
else
{
int iTotal;
int * paiEmpireUserCount;
int iLocal;
DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal);
snprintf(szTmp, sizeof(szTmp), "%d %d %d %d %d", iTotal, paiEmpireUserCount[1], paiEmpireUserCount[2], paiEmpireUserCount[3], iLocal);
}
stResult += szTmp;
}
else if (!stBuf.compare("CHECK_P2P_CONNECTIONS"))
{
std::ostringstream oss(std::ostringstream::out);
oss << "P2P CONNECTION NUMBER : " << P2P_MANAGER::instance().GetDescCount() << "\n";
std::string hostNames;
P2P_MANAGER::Instance().GetP2PHostNames(hostNames);
oss << hostNames;
stResult = oss.str();
TPacketGGCheckAwakeness packet;
packet.bHeader = HEADER_GG_CHECK_AWAKENESS;
P2P_MANAGER::instance().Send(&packet, sizeof(packet));
}
else if (!stBuf.compare("PACKET_INFO"))
{
m_pMainPacketInfo->Log("packet_info.txt");
stResult = "OK";
}
else if (!stBuf.compare("PROFILE"))
{
CProfiler::instance().Log("profile.txt");
stResult = "OK";
}
//gift notify delete command
else if (!stBuf.compare(0,15,"DELETE_AWARDID "))
{
char szTmp[64];
std::string msg = stBuf.substr(15,26); // item_award의 id범위?
TPacketDeleteAwardID p;
p.dwID = (DWORD)(atoi(msg.c_str()));
snprintf(szTmp,sizeof(szTmp),"Sent to DB cache to delete ItemAward, id: %d",p.dwID);
//sys_log(0,"%d",p.dwID);
// strlcpy(p.login, msg.c_str(), sizeof(p.login));
db_clientdesc->DBPacket(HEADER_GD_DELETE_AWARDID, 0, &p, sizeof(p));
stResult += szTmp;
}
else
{
stResult = "UNKNOWN";
if (d->IsAdminMode())
{
// 어드민 명령들
if (!stBuf.compare(0, 7, "NOTICE "))
{
std::string msg = stBuf.substr(7, 50);
LogManager::instance().CharLog(0, 0, 0, 1, "NOTICE", msg.c_str(), d->GetHostName());
BroadcastNotice(msg.c_str());
}
else if (!stBuf.compare("CLOSE_PASSPOD"))
{
g_bNoPasspod = true;
stResult += "CLOSE_PASSPOD";
}
else if (!stBuf.compare("OPEN_PASSPOD"))
{
g_bNoPasspod = false;
stResult += "OPEN_PASSPOD";
}
else if (!stBuf.compare("SHUTDOWN"))
{
LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName());
TPacketGGShutdown p;
p.bHeader = HEADER_GG_SHUTDOWN;
P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShutdown));
sys_err("Accept shutdown command from %s.", d->GetHostName());
Shutdown(10);
}
else if (!stBuf.compare("SHUTDOWN_ONLY"))
{
LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName());
sys_err("Accept shutdown only command from %s.", d->GetHostName());
Shutdown(10);
}
else if (!stBuf.compare(0, 3, "DC "))
{
std::string msg = stBuf.substr(3, LOGIN_MAX_LEN);
dev_log(LOG_DEB0, "DC : '%s'", msg.c_str());
TPacketGGDisconnect pgg;
pgg.bHeader = HEADER_GG_DISCONNECT;
strlcpy(pgg.szLogin, msg.c_str(), sizeof(pgg.szLogin));
P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGDisconnect));
// delete login key
{
TPacketDC p;
strlcpy(p.login, msg.c_str(), sizeof(p.login));
db_clientdesc->DBPacket(HEADER_GD_DC, 0, &p, sizeof(p));
}
}
else if (!stBuf.compare(0, 10, "RELOAD_CRC"))
{
LoadValidCRCList();
BYTE bHeader = HEADER_GG_RELOAD_CRC_LIST;
P2P_MANAGER::instance().Send(&bHeader, sizeof(BYTE));
stResult = "OK";
}
else if (!stBuf.compare(0, 20, "CHECK_CLIENT_VERSION"))
{
CheckClientVersion();
BYTE bHeader = HEADER_GG_CHECK_CLIENT_VERSION;
P2P_MANAGER::instance().Send(&bHeader, sizeof(BYTE));
stResult = "OK";
}
else if (!stBuf.compare(0, 6, "RELOAD"))
{
if (stBuf.size() == 6)
{
LoadStateUserCount();
db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, NULL, 0);
DBManager::instance().LoadDBString();
}
else
{
char c = stBuf[7];
switch (LOWER(c))
{
case 'u':
LoadStateUserCount();
break;
case 'p':
db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, NULL, 0);
break;
case 's':
DBManager::instance().LoadDBString();
break;
case 'q':
quest::CQuestManager::instance().Reload();
break;
case 'f':
fishing::Initialize();
break;
case 'a':
db_clientdesc->DBPacket(HEADER_GD_RELOAD_ADMIN, 0, NULL, 0);
sys_log(0, "Reloading admin infomation.");
break;
}
}
}
else if (!stBuf.compare(0, 6, "EVENT "))
{
std::istringstream is(stBuf);
std::string strEvent, strFlagName;
long lValue;
is >> strEvent >> strFlagName >> lValue;
if (!is.fail())
{
sys_log(0, "EXTERNAL EVENT FLAG name %s value %d", strFlagName.c_str(), lValue);
quest::CQuestManager::instance().RequestSetEventFlag(strFlagName, lValue);
stResult = "EVENT FLAG CHANGE ";
stResult += strFlagName;
}
else
{
stResult = "EVENT FLAG FAIL";
}
}
// BLOCK_CHAT
else if (!stBuf.compare(0, 11, "BLOCK_CHAT "))
{
std::istringstream is(stBuf);
std::string strBlockChat, strCharName;
long lDuration;
is >> strBlockChat >> strCharName >> lDuration;
if (!is.fail())
{
sys_log(0, "EXTERNAL BLOCK_CHAT name %s duration %d", strCharName.c_str(), lDuration);
do_block_chat(NULL, const_cast<char*>(stBuf.c_str() + 11), 0, 0);
stResult = "BLOCK_CHAT ";
stResult += strCharName;
}
else
{
stResult = "BLOCK_CHAT FAIL";
}
}
// END_OF_BLOCK_CHAT
else if (!stBuf.compare(0, 12, "PRIV_EMPIRE "))
{
int empire, type, value, duration;
std::istringstream is(stBuf);
std::string strPrivEmpire;
is >> strPrivEmpire >> empire >> type >> value >> duration;
// 최대치 10배
value = MINMAX(0, value, 1000);
stResult = "PRIV_EMPIRE FAIL";
if (!is.fail())
{
// check parameter
if (empire < 0 || 3 < empire);
else if (type < 1 || 4 < type);
else if (value < 0);
else if (duration < 0);
else
{
stResult = "PRIV_EMPIRE SUCCEED";
// 시간 단위로 변경
duration = duration * (60 * 60);
sys_log(0, "_give_empire_privileage(empire=%d, type=%d, value=%d, duration=%d) by web",
empire, type, value, duration);
CPrivManager::instance().RequestGiveEmpirePriv(empire, type, value, duration);
}
}
}
else if (!stBuf.compare(0, 15, "BLOCK_EXCEPTION"))
{
// BLOCK_EXCEPTION cmd(add=1, del=2) login
std::istringstream is(stBuf);
std::string dummy_string;
std::string login_string;
int cmd;
is >> dummy_string >> cmd >> login_string;
sys_log(0, "block_exception %s:%d", login_string.c_str(), cmd);
DBManager::instance().RequestBlockException(login_string.c_str(), cmd);
stResult = "BLOCK_EXCEPTION_YES";
}
}
}
sys_log(1, "TEXT %s RESULT %s", stBuf.c_str(), stResult.c_str());
stResult += "\n";
d->Packet(stResult.c_str(), stResult.length());
return (c_pSep - c_pData) + 1;
}
else if (bHeader == HEADER_CG_MARK_LOGIN)
{
if (!guild_mark_server)
{
// 끊어버려! - 마크 서버가 아닌데 마크를 요청하려고?
sys_err("Guild Mark login requested but i'm not a mark server!");
d->SetPhase(PHASE_CLOSE);
return 0;
}
// 무조건 인증 --;
sys_log(0, "MARK_SERVER: Login");
d->SetPhase(PHASE_LOGIN);
return 0;
}
else if (bHeader == HEADER_CG_STATE_CHECKER)
{
if (d->isChannelStatusRequested()) {
return 0;
}
d->SetChannelStatusRequested(true);
db_clientdesc->DBPacket(HEADER_GD_REQUEST_CHANNELSTATUS, d->GetHandle(), NULL, 0);
}
else if (bHeader == HEADER_CG_PONG)
Pong(d);
else if (bHeader == HEADER_CG_HANDSHAKE)
Handshake(d, c_pData);
#ifdef _IMPROVED_PACKET_ENCRYPTION_
else if (bHeader == HEADER_CG_KEY_AGREEMENT)
{
// Send out the key agreement completion packet first
// to help client to enter encryption mode
d->SendKeyAgreementCompleted();
// Flush socket output before going encrypted
d->ProcessOutput();
TPacketKeyAgreement* p = (TPacketKeyAgreement*)c_pData;
if (!d->IsCipherPrepared())
{
sys_err ("Cipher isn't prepared. %s maybe a Hacker.", inet_ntoa(d->GetAddr().sin_addr));
d->DelayedDisconnect(5);
return 0;
}
if (d->FinishHandshake(p->wAgreedLength, p->data, p->wDataLength)) {
// Handshaking succeeded
if (g_bAuthServer) {
d->SetPhase(PHASE_AUTH);
} else {
d->SetPhase(PHASE_LOGIN);
}
} else {
sys_log(0, "[CInputHandshake] Key agreement failed: al=%u dl=%u",
p->wAgreedLength, p->wDataLength);
d->SetPhase(PHASE_CLOSE);
}
}
#endif // _IMPROVED_PACKET_ENCRYPTION_
else
sys_err("Handshake phase does not handle packet %d (fd %d)", bHeader, d->GetSocket());
return 0;
}#include "stdafx.h"
#include "config.h"
#include "utils.h"
#include "desc.h"
#include "desc_client.h"
#include "desc_manager.h"
#include "char.h"
#include "protocol.h"
#include "packet.h"
#include "messenger_manager.h"
#include "sectree_manager.h"
#include "p2p.h"
#include "buffer_manager.h"
#include "sequence.h"
#include "guild.h"
#include "guild_manager.h"
#include "TrafficProfiler.h"
#include "locale_service.h"
#include "log.h"
extern int max_bytes_written;
extern int current_bytes_written;
extern int total_bytes_written;
DESC::DESC()
{
Initialize();
}
DESC::~DESC()
{
}
void DESC::Initialize()
{
m_bDestroyed = false;
m_pInputProcessor = NULL;
m_lpFdw = NULL;
m_sock = INVALID_SOCKET;
m_iPhase = PHASE_CLOSE;
m_dwHandle = 0;
m_wPort = 0;
m_LastTryToConnectTime = 0;
m_lpInputBuffer = NULL;
m_iMinInputBufferLen = 0;
m_dwHandshake = 0;
m_dwHandshakeSentTime = 0;
m_iHandshakeRetry = 0;
m_dwClientTime = 0;
m_bHandshaking = false;
m_lpBufferedOutputBuffer = NULL;
m_lpOutputBuffer = NULL;
m_pkPingEvent = NULL;
m_lpCharacter = NULL;
memset( &m_accountTable, 0, sizeof(m_accountTable) );
memset( &m_SockAddr, 0, sizeof(m_SockAddr) );
memset( &m_UDPSockAddr, 0, sizeof(m_UDPSockAddr) );
m_pLogFile = NULL;
#ifndef _IMPROVED_PACKET_ENCRYPTION_
m_bEncrypted = false;
#endif
m_wP2PPort = 0;
m_bP2PChannel = 0;
m_bAdminMode = false;
m_bPong = true;
m_bChannelStatusRequested = false;
m_iCurrentSequence = 0;
m_dwMatrixRows = m_dwMatrixCols = 0;
m_bMatrixTryCount = 0;
m_pkLoginKey = NULL;
m_dwLoginKey = 0;
m_dwPanamaKey = 0;
#ifndef _IMPROVED_PACKET_ENCRYPTION_
memset( m_adwDecryptionKey, 0, sizeof(m_adwDecryptionKey) );
memset( m_adwEncryptionKey, 0, sizeof(m_adwEncryptionKey) );
#endif
m_bCRCMagicCubeIdx = 0;
m_dwProcCRC = 0;
m_dwFileCRC = 0;
m_bHackCRCQuery = 0;
m_dwBillingExpireSecond = 0;
m_outtime = 0;
m_playtime = 0;
m_offtime = 0;
m_pkDisconnectEvent = NULL;
m_seq_vector.clear();
}
void DESC::Destroy()
{
if (m_bDestroyed) {
return;
}
m_bDestroyed = true;
if (m_pkLoginKey)
m_pkLoginKey->Expire();
if (GetAccountTable().id)
DESC_MANAGER::instance().DisconnectAccount(GetAccountTable().login);
if (m_pLogFile)
{
fclose(m_pLogFile);
m_pLogFile = NULL;
}
if (m_lpCharacter)
{
m_lpCharacter->Disconnect("DESC::~DESC");
m_lpCharacter = NULL;
}
SAFE_BUFFER_DELETE(m_lpOutputBuffer);
SAFE_BUFFER_DELETE(m_lpInputBuffer);
event_cancel(&m_pkPingEvent);
event_cancel(&m_pkDisconnectEvent);
if (!g_bAuthServer)
{
if (m_accountTable.login[0] && m_accountTable.passwd[0])
{
TLogoutPacket pack;
strlcpy(pack.login, m_accountTable.login, sizeof(pack.login));
strlcpy(pack.passwd, m_accountTable.passwd, sizeof(pack.passwd));
db_clientdesc->DBPacket(HEADER_GD_LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket));
}
}
if (m_sock != INVALID_SOCKET)
{
sys_log(0, "SYSTEM: closing socket. DESC #%d", m_sock);
Log("SYSTEM: closing socket. DESC #%d", m_sock);
fdwatch_del_fd(m_lpFdw, m_sock);
#ifdef _IMPROVED_PACKET_ENCRYPTION_
cipher_.CleanUp();
#endif
socket_close(m_sock);
m_sock = INVALID_SOCKET;
}
m_seq_vector.clear();
}
EVENTFUNC(ping_event)
{
DESC::desc_event_info* info = dynamic_cast<DESC::desc_event_info*>( event->info );
if ( info == NULL )
{
sys_err( "ping_event> <Factor> Null pointer" );
return 0;
}
LPDESC desc = info->desc;
if (desc->IsAdminMode())
return (ping_event_second_cycle);
if (!desc->IsPong())
{
sys_log(0, "PING_EVENT: no pong %s", desc->GetHostName());
desc->SetPhase(PHASE_CLOSE);
return (ping_event_second_cycle);
}
else
{
TPacketGCPing p;
p.header = HEADER_GC_PING;
desc->Packet(&p, sizeof(struct packet_ping));
desc->SetPong(false);
}
#ifdef ENABLE_LIMIT_TIME
if ((unsigned)get_global_time() >= GLOBAL_LIMIT_TIME)
{
extern void ClearAdminPages();
ClearAdminPages();
extern g_bShutdown;
g_bShutdown = true;
}
#endif
desc->SendHandshake(get_dword_time(), 0);
return (ping_event_second_cycle);
}
bool DESC::IsPong()
{
return m_bPong;
}
void DESC::SetPong(bool b)
{
m_bPong = b;
}
bool DESC::Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSockAddr, DWORD _handle, DWORD _handshake)
{
m_lpFdw = _fdw;
m_sock = _fd;
m_stHost = inet_ntoa(c_rSockAddr.sin_addr);
m_wPort = c_rSockAddr.sin_port;
m_dwHandle = _handle;
//if (LC_IsEurope() == true || LC_IsNewCIBN())
// m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2);
//else
//NOTE: 이걸 나라별로 다르게 잡아야할 이유가 있나?
m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2);
m_iMinInputBufferLen = MAX_INPUT_LEN >> 1;
m_lpInputBuffer = buffer_new(MAX_INPUT_LEN);
m_SockAddr = c_rSockAddr;
fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_READ, false);
// Ping Event
desc_event_info* info = AllocEventInfo<desc_event_info>();
info->desc = this;
assert(m_pkPingEvent == NULL);
m_pkPingEvent = event_create(ping_event, info, ping_event_second_cycle);
#ifndef _IMPROVED_PACKET_ENCRYPTION_
if (LC_IsEurope())
{
thecore_memcpy(m_adwEncryptionKey, "1234abcd5678efgh", sizeof(DWORD) * 4);
thecore_memcpy(m_adwDecryptionKey, "1234abcd5678efgh", sizeof(DWORD) * 4);
}
else
{
thecore_memcpy(m_adwEncryptionKey, "testtesttesttest", sizeof(DWORD) * 4);
thecore_memcpy(m_adwDecryptionKey, "testtesttesttest", sizeof(DWORD) * 4);
}
#endif // _IMPROVED_PACKET_ENCRYPTION_
// Set Phase to handshake
SetPhase(PHASE_HANDSHAKE);
StartHandshake(_handshake);
sys_log(0, "SYSTEM: new connection from [%s] fd: %d handshake %u output input_len %d, ptr %p",
m_stHost.c_str(), m_sock, m_dwHandshake, buffer_size(m_lpInputBuffer), this);
Log("SYSTEM: new connection from [%s] fd: %d handshake %u ptr %p", m_stHost.c_str(), m_sock, m_dwHandshake, this);
return true;
}
int DESC::ProcessInput()
{
ssize_t bytes_read;
if (!m_lpInputBuffer)
{
sys_err("DESC::ProcessInput : nil input buffer");
return -1;
}
buffer_adjust_size(m_lpInputBuffer, m_iMinInputBufferLen);
bytes_read = socket_read(m_sock, (char *) buffer_write_peek(m_lpInputBuffer), buffer_has_space(m_lpInputBuffer));
if (bytes_read < 0)
return -1;
else if (bytes_read == 0)
return 0;
buffer_write_proceed(m_lpInputBuffer, bytes_read);
if (!m_pInputProcessor)
sys_err("no input processor");
#ifdef _IMPROVED_PACKET_ENCRYPTION_
else
{
if (cipher_.activated()) {
cipher_.Decrypt(const_cast<void*>(buffer_read_peek(m_lpInputBuffer)), buffer_size(m_lpInputBuffer));
}
int iBytesProceed = 0;
// false가 리턴 되면 다른 phase로 바뀐 것이므로 다시 프로세스로 돌입한다!
while (!m_pInputProcessor->Process(this, buffer_read_peek(m_lpInputBuffer), buffer_size(m_lpInputBuffer), iBytesProceed))
{
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
iBytesProceed = 0;
}
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
}
#else
else if (!m_bEncrypted)
{
int iBytesProceed = 0;
// false가 리턴 되면 다른 phase로 바뀐 것이므로 다시 프로세스로 돌입한다!
while (!m_pInputProcessor->Process(this, buffer_read_peek(m_lpInputBuffer), buffer_size(m_lpInputBuffer), iBytesProceed))
{
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
iBytesProceed = 0;
}
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
}
else
{
int iSizeBuffer = buffer_size(m_lpInputBuffer);
// 8바이트 단위로만 처리한다. 8바이트 단위에 부족하면 잘못된 암호화 버퍼를 복호화
// 할 가능성이 있으므로 짤라서 처리하기로 한다.
if (iSizeBuffer & 7) // & 7은 % 8과 같다. 2의 승수에서만 가능
iSizeBuffer -= iSizeBuffer & 7;
if (iSizeBuffer > 0)
{
TEMP_BUFFER tempbuf;
LPBUFFER lpBufferDecrypt = tempbuf.getptr();
buffer_adjust_size(lpBufferDecrypt, iSizeBuffer);
int iSizeAfter = TEA_Decrypt((DWORD *) buffer_write_peek(lpBufferDecrypt),
(DWORD *) buffer_read_peek(m_lpInputBuffer),
GetDecryptionKey(),
iSizeBuffer);
buffer_write_proceed(lpBufferDecrypt, iSizeAfter);
int iBytesProceed = 0;
// false가 리턴 되면 다른 phase로 바뀐 것이므로 다시 프로세스로 돌입한다!
while (!m_pInputProcessor->Process(this, buffer_read_peek(lpBufferDecrypt), buffer_size(lpBufferDecrypt), iBytesProceed))
{
if (iBytesProceed > iSizeBuffer)
{
buffer_read_proceed(m_lpInputBuffer, iSizeBuffer);
iSizeBuffer = 0;
iBytesProceed = 0;
break;
}
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
iSizeBuffer -= iBytesProceed;
buffer_read_proceed(lpBufferDecrypt, iBytesProceed);
iBytesProceed = 0;
}
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
}
}
#endif // _IMPROVED_PACKET_ENCRYPTION_
return (bytes_read);
}
int DESC::ProcessOutput()
{
if (buffer_size(m_lpOutputBuffer) <= 0)
return 0;
int buffer_left = fdwatch_get_buffer_size(m_lpFdw, m_sock);
if (buffer_left <= 0)
return 0;
int bytes_to_write = MIN(buffer_left, buffer_size(m_lpOutputBuffer));
if (bytes_to_write == 0)
return 0;
int result = socket_write(m_sock, (const char *) buffer_read_peek(m_lpOutputBuffer), bytes_to_write);
if (result == 0)
{
//sys_log(0, "%d bytes written to %s first %u", bytes_to_write, GetHostName(), *(BYTE *) buffer_read_peek(m_lpOutputBuffer));
//Log("%d bytes written", bytes_to_write);
max_bytes_written = MAX(bytes_to_write, max_bytes_written);
total_bytes_written += bytes_to_write;
current_bytes_written += bytes_to_write;
buffer_read_proceed(m_lpOutputBuffer, bytes_to_write);
if (buffer_size(m_lpOutputBuffer) != 0)
fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true);
}
return (result);
}
void DESC::BufferedPacket(const void * c_pvData, int iSize)
{
if (m_iPhase == PHASE_CLOSE)
return;
if (!m_lpBufferedOutputBuffer)
m_lpBufferedOutputBuffer = buffer_new(MAX(1024, iSize));
buffer_write(m_lpBufferedOutputBuffer, c_pvData, iSize);
}
void DESC::Packet(const void * c_pvData, int iSize)
{
assert(iSize > 0);
if (m_iPhase == PHASE_CLOSE) // 끊는 상태면 보내지 않는다.
return;
if (m_stRelayName.length() != 0)
{
// Relay 패킷은 암호화하지 않는다.
TPacketGGRelay p;
p.bHeader = HEADER_GG_RELAY;
strlcpy(p.szName, m_stRelayName.c_str(), sizeof(p.szName));
p.lSize = iSize;
if (!packet_encode(m_lpOutputBuffer, &p, sizeof(p)))
{
m_iPhase = PHASE_CLOSE;
return;
}
m_stRelayName.clear();
if (!packet_encode(m_lpOutputBuffer, c_pvData, iSize))
{
m_iPhase = PHASE_CLOSE;
return;
}
}
else
{
if (m_lpBufferedOutputBuffer)
{
buffer_write(m_lpBufferedOutputBuffer, c_pvData, iSize);
c_pvData = buffer_read_peek(m_lpBufferedOutputBuffer);
iSize = buffer_size(m_lpBufferedOutputBuffer);
}
// TRAFFIC_PROFILE
if (g_bTrafficProfileOn)
TrafficProfiler::instance().Report(TrafficProfiler::IODIR_OUTPUT, *(BYTE *) c_pvData, iSize);
// END_OF_TRAFFIC_PROFILER
#ifdef _IMPROVED_PACKET_ENCRYPTION_
void* buf = buffer_write_peek(m_lpOutputBuffer);
if (packet_encode(m_lpOutputBuffer, c_pvData, iSize))
{
if (cipher_.activated()) {
cipher_.Encrypt(buf, iSize);
}
}
else
{
m_iPhase = PHASE_CLOSE;
}
#else
if (!m_bEncrypted)
{
if (!packet_encode(m_lpOutputBuffer, c_pvData, iSize))
{
m_iPhase = PHASE_CLOSE;
}
}
else
{
if (buffer_has_space(m_lpOutputBuffer) < iSize + 8)
{
sys_err("desc buffer mem_size overflow. memsize(%u) write_pos(%u) iSize(%d)",
m_lpOutputBuffer->mem_size, m_lpOutputBuffer->write_point_pos, iSize);
m_iPhase = PHASE_CLOSE;
}
else
{
// 암호화에 필요한 충분한 버퍼 크기를 확보한다.
/* buffer_adjust_size(m_lpOutputBuffer, iSize + 8); */
DWORD * pdwWritePoint = (DWORD *) buffer_write_peek(m_lpOutputBuffer);
if (packet_encode(m_lpOutputBuffer, c_pvData, iSize))
{
int iSize2 = TEA_Encrypt(pdwWritePoint, pdwWritePoint, GetEncryptionKey(), iSize);
if (iSize2 > iSize)
buffer_write_proceed(m_lpOutputBuffer, iSize2 - iSize);
}
}
}
#endif // _IMPROVED_PACKET_ENCRYPTION_
SAFE_BUFFER_DELETE(m_lpBufferedOutputBuffer);
}
//sys_log(0, "%d bytes written (first byte %d)", iSize, *(BYTE *) c_pvData);
if (m_iPhase != PHASE_CLOSE)
fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true);
}
void DESC::LargePacket(const void * c_pvData, int iSize)
{
buffer_adjust_size(m_lpOutputBuffer, iSize);
sys_log(0, "LargePacket Size %d", iSize, buffer_size(m_lpOutputBuffer));
Packet(c_pvData, iSize);
}
void DESC::SetPhase(int _phase)
{
m_iPhase = _phase;
TPacketGCPhase pack;
pack.header = HEADER_GC_PHASE;
pack.phase = _phase;
Packet(&pack, sizeof(TPacketGCPhase));
switch (m_iPhase)
{
case PHASE_CLOSE:
// 메신저가 캐릭터단위가 되면서 삭제
//MessengerManager::instance().Logout(GetAccountTable().login);
m_pInputProcessor = &m_inputClose;
break;
case PHASE_HANDSHAKE:
m_pInputProcessor = &m_inputHandshake;
break;
case PHASE_SELECT:
// 메신저가 캐릭터단위가 되면서 삭제
//MessengerManager::instance().Logout(GetAccountTable().login); // 의도적으로 break 안검
case PHASE_LOGIN:
case PHASE_LOADING:
#ifndef _IMPROVED_PACKET_ENCRYPTION_
m_bEncrypted = true;
#endif
m_pInputProcessor = &m_inputLogin;
break;
case PHASE_GAME:
case PHASE_DEAD:
#ifndef _IMPROVED_PACKET_ENCRYPTION_
m_bEncrypted = true;
#endif
m_pInputProcessor = &m_inputMain;
break;
case PHASE_AUTH:
#ifndef _IMPROVED_PACKET_ENCRYPTION_
m_bEncrypted = true;
#endif
m_pInputProcessor = &m_inputAuth;
sys_log(0, "AUTH_PHASE %p", this);
break;
}
}
void DESC::BindAccountTable(TAccountTable * pAccountTable)
{
assert(pAccountTable != NULL);
thecore_memcpy(&m_accountTable, pAccountTable, sizeof(TAccountTable));
DESC_MANAGER::instance().ConnectAccount(m_accountTable.login, this);
}
void DESC::UDPGrant(const struct sockaddr_in & c_rSockAddr)
{
m_UDPSockAddr = c_rSockAddr;
TPacketGCBindUDP pack;
pack.header = HEADER_GC_BINDUDP;
pack.addr = m_UDPSockAddr.sin_addr.s_addr;
pack.port = m_UDPSockAddr.sin_port;
Packet(&pack, sizeof(TPacketGCBindUDP));
}
void DESC::Log(const char * format, ...)
{
if (!m_pLogFile)
return;
va_list args;
time_t ct = get_global_time();
struct tm tm = *localtime(&ct);
fprintf(m_pLogFile,
"%02d %02d %02d:%02d:%02d | ",
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec);
va_start(args, format);
vfprintf(m_pLogFile, format, args);
va_end(args);
fputs("\n", m_pLogFile);
fflush(m_pLogFile);
}
void DESC::StartHandshake(DWORD _handshake)
{
// Handshake
m_dwHandshake = _handshake;
SendHandshake(get_dword_time(), 0);
m_iHandshakeRetry = 0;
}
void DESC::SendHandshake(DWORD dwCurTime, long lNewDelta)
{
TPacketGCHandshake pack;
pack.bHeader = HEADER_GC_HANDSHAKE;
pack.dwHandshake = m_dwHandshake;
pack.dwTime = dwCurTime;
pack.lDelta = lNewDelta;
Packet(&pack, sizeof(TPacketGCHandshake));
m_dwHandshakeSentTime = dwCurTime;
m_bHandshaking = true;
}
bool DESC::HandshakeProcess(DWORD dwTime, long lDelta, bool bInfiniteRetry)
{
DWORD dwCurTime = get_dword_time();
if (lDelta < 0)
{
sys_err("Desc::HandshakeProcess : value error (lDelta %d, ip %s)", lDelta, m_stHost.c_str());
return false;
}
int bias = (int) (dwCurTime - (dwTime + lDelta));
if (bias >= 0 && bias <= 50)
{
if (bInfiniteRetry)
{
BYTE bHeader = HEADER_GC_TIME_SYNC;
Packet(&bHeader, sizeof(BYTE));
}
if (GetCharacter())
sys_log(0, "Handshake: client_time %u server_time %u name: %s", m_dwClientTime, dwCurTime, GetCharacter()->GetName());
else
sys_log(0, "Handshake: client_time %u server_time %u", m_dwClientTime, dwCurTime, lDelta);
m_dwClientTime = dwCurTime;
m_bHandshaking = false;
return true;
}
long lNewDelta = (long) (dwCurTime - dwTime) / 2;
if (lNewDelta < 0)
{
sys_log(0, "Handshake: lower than zero %d", lNewDelta);
lNewDelta = (dwCurTime - m_dwHandshakeSentTime) / 2;
}
sys_log(1, "Handshake: ServerTime %u dwTime %u lDelta %d SentTime %u lNewDelta %d", dwCurTime, dwTime, lDelta, m_dwHandshakeSentTime, lNewDelta);
if (!bInfiniteRetry)
if (++m_iHandshakeRetry > HANDSHAKE_RETRY_LIMIT)
{
sys_err("handshake retry limit reached! (limit %d character %s)",
HANDSHAKE_RETRY_LIMIT, GetCharacter() ? GetCharacter()->GetName() : "!NO CHARACTER!");
SetPhase(PHASE_CLOSE);
return false;
}
SendHandshake(dwCurTime, lNewDelta);
return false;
}
bool DESC::IsHandshaking()
{
return m_bHandshaking;
}
DWORD DESC::GetClientTime()
{
return m_dwClientTime;
}
#ifdef _IMPROVED_PACKET_ENCRYPTION_
void DESC::SendKeyAgreement()
{
TPacketKeyAgreement packet;
size_t data_length = TPacketKeyAgreement::MAX_DATA_LEN;
size_t agreed_length = cipher_.Prepare(packet.data, &data_length);
if (agreed_length == 0) {
// Initialization failure
SetPhase(PHASE_CLOSE);
return;
}
assert(data_length <= TPacketKeyAgreement::MAX_DATA_LEN);
packet.bHeader = HEADER_GC_KEY_AGREEMENT;
packet.wAgreedLength = (WORD)agreed_length;
packet.wDataLength = (WORD)data_length;
Packet(&packet, sizeof(packet));
}
void DESC::SendKeyAgreementCompleted()
{
TPacketKeyAgreementCompleted packet;
packet.bHeader = HEADER_GC_KEY_AGREEMENT_COMPLETED;
Packet(&packet, sizeof(packet));
}
bool DESC::FinishHandshake(size_t agreed_length, const void* buffer, size_t length)
{
return cipher_.Activate(false, agreed_length, buffer, length);
}
bool DESC::IsCipherPrepared()
{
return cipher_.IsKeyPrepared();
}
#endif // #ifdef _IMPROVED_PACKET_ENCRYPTION_
void DESC::SetRelay(const char * c_pszName)
{
m_stRelayName = c_pszName;
}
void DESC::BindCharacter(LPCHARACTER ch)
{
m_lpCharacter = ch;
}
void DESC::FlushOutput()
{
if (m_sock == INVALID_SOCKET) {
return;
}
if (buffer_size(m_lpOutputBuffer) <= 0)
return;
struct timeval sleep_tv, now_tv, start_tv;
int event_triggered = false;
gettimeofday(&start_tv, NULL);
socket_block(m_sock);
sys_log(0, "FLUSH START %d", buffer_size(m_lpOutputBuffer));
while (buffer_size(m_lpOutputBuffer) > 0)
{
gettimeofday(&now_tv, NULL);
int iSecondsPassed = now_tv.tv_sec - start_tv.tv_sec;
if (iSecondsPassed > 10)
{
if (!event_triggered || iSecondsPassed > 20)
{
SetPhase(PHASE_CLOSE);
break;
}
}
sleep_tv.tv_sec = 0;
sleep_tv.tv_usec = 10000;
int num_events = fdwatch(m_lpFdw, &sleep_tv);
if (num_events < 0)
{
sys_err("num_events < 0 : %d", num_events);
break;
}
int event_idx;
for (event_idx = 0; event_idx < num_events; ++event_idx)
{
LPDESC d2 = (LPDESC) fdwatch_get_client_data(m_lpFdw, event_idx);
if (d2 != this)
continue;
switch (fdwatch_check_event(m_lpFdw, m_sock, event_idx))
{
case FDW_WRITE:
event_triggered = true;
if (ProcessOutput() < 0)
{
sys_err("Cannot flush output buffer");
SetPhase(PHASE_CLOSE);
}
break;
case FDW_EOF:
SetPhase(PHASE_CLOSE);
break;
}
}
if (IsPhase(PHASE_CLOSE))
break;
}
if (buffer_size(m_lpOutputBuffer) == 0)
sys_log(0, "FLUSH SUCCESS");
else
sys_log(0, "FLUSH FAIL");
usleep(250000);
}
EVENTFUNC(disconnect_event)
{
DESC::desc_event_info* info = dynamic_cast<DESC::desc_event_info*>( event->info );
if ( info == NULL )
{
sys_err( "disconnect_event> <Factor> Null pointer" );
return 0;
}
LPDESC d = info->desc;
d->m_pkDisconnectEvent = NULL;
d->SetPhase(PHASE_CLOSE);
return 0;
}
bool DESC::DelayedDisconnect(int iSec)
{
if (m_pkDisconnectEvent != NULL) {
return false;
}
desc_event_info* info = AllocEventInfo<desc_event_info>();
info->desc = this;
m_pkDisconnectEvent = event_create(disconnect_event, info, PASSES_PER_SEC(iSec));
return true;
}
void DESC::DisconnectOfSameLogin()
{
if (GetCharacter())
{
if (m_pkDisconnectEvent)
return;
GetCharacter()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 컴퓨터에서 로그인 하여 접속을 종료 합니다."));
DelayedDisconnect(5);
}
else
{
SetPhase(PHASE_CLOSE);
}
}
void DESC::SetAdminMode()
{
m_bAdminMode = true;
}
bool DESC::IsAdminMode()
{
return m_bAdminMode;
}
BYTE DESC::GetSequence()
{
return gc_abSequence[m_iCurrentSequence];
}
void DESC::SetNextSequence()
{
if (++m_iCurrentSequence == SEQUENCE_MAX_NUM)
m_iCurrentSequence = 0;
}
void DESC::SendLoginSuccessPacket()
{
TAccountTable & rTable = GetAccountTable();
TPacketGCLoginSuccess p;
p.bHeader = HEADER_GC_LOGIN_SUCCESS_NEWSLOT;
p.handle = GetHandle();
p.random_key = DESC_MANAGER::instance().MakeRandomKey(GetHandle()); // FOR MARK
thecore_memcpy(p.players, rTable.players, sizeof(rTable.players));
for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
{
CGuild* g = CGuildManager::instance().GetLinkedGuild(rTable.players[i].dwID);
if (g)
{
p.guild_id[i] = g->GetID();
strlcpy(p.guild_name[i], g->GetName(), sizeof(p.guild_name[i]));
}
else
{
p.guild_id[i] = 0;
p.guild_name[i][0] = '\0';
}
}
Packet(&p, sizeof(TPacketGCLoginSuccess));
}
//void DESC::SendServerStatePacket(int nIndex)
//{
// TPacketGCStateCheck rp;
//
// int iTotal;
// int * paiEmpireUserCount;
// int iLocal;
//
// DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal);
//
// rp.header = 1;
// rp.key = 0;
// rp.index = nIndex;
//
// if (g_bNoMoreClient) rp.state = 0;
// else rp.state = iTotal > g_iFullUserCount ? 3 : iTotal > g_iBusyUserCount ? 2 : 1;
//
// this->Packet(&rp, sizeof(rp));
// //printf("STATE_CHECK PACKET PROCESSED.\n");
//}
void DESC::SetMatrixCardRowsAndColumns(unsigned long rows, unsigned long cols)
{
m_dwMatrixRows = rows;
m_dwMatrixCols = cols;
}
unsigned long DESC::GetMatrixRows()
{
return m_dwMatrixRows;
}
unsigned long DESC::GetMatrixCols()
{
return m_dwMatrixCols;
}
bool DESC::CheckMatrixTryCount()
{
if (++m_bMatrixTryCount >= 3)
return false;
return true;
}
void DESC::SetLoginKey(DWORD dwKey)
{
m_dwLoginKey = dwKey;
}
void DESC::SetLoginKey(CLoginKey * pkKey)
{
m_pkLoginKey = pkKey;
sys_log(0, "SetLoginKey %u", m_pkLoginKey->m_dwKey);
}
DWORD DESC::GetLoginKey()
{
if (m_pkLoginKey)
return m_pkLoginKey->m_dwKey;
return m_dwLoginKey;
}
const BYTE* GetKey_20050304Myevan()
{
static bool bGenerated = false;
static DWORD s_adwKey[1938];
if (!bGenerated)
{
bGenerated = true;
DWORD seed = 1491971513;
for (UINT i = 0; i < BYTE(seed); ++i)
{
seed ^= 2148941891ul;
seed += 3592385981ul;
s_adwKey[i] = seed;
}
}
return (const BYTE*)s_adwKey;
}
#ifndef _IMPROVED_PACKET_ENCRYPTION_
void DESC::SetSecurityKey(const DWORD * c_pdwKey)
{
const BYTE * c_pszKey = (const BYTE *) "JyTxtHljHJlVJHorRM301vf@4fvj10-v";
if (g_iUseLocale && !LC_IsKorea())
c_pszKey = GetKey_20050304Myevan() + 37;
thecore_memcpy(&m_adwDecryptionKey, c_pdwKey, 16);
TEA_Encrypt(&m_adwEncryptionKey[0], &m_adwDecryptionKey[0], (const DWORD *) c_pszKey, 16);
sys_log(0, "SetSecurityKey decrypt %u %u %u %u encrypt %u %u %u %u",
m_adwDecryptionKey[0], m_adwDecryptionKey[1], m_adwDecryptionKey[2], m_adwDecryptionKey[3],
m_adwEncryptionKey[0], m_adwEncryptionKey[1], m_adwEncryptionKey[2], m_adwEncryptionKey[3]);
}
#endif // _IMPROVED_PACKET_ENCRYPTION_
void DESC::AssembleCRCMagicCube(BYTE bProcPiece, BYTE bFilePiece)
{
static BYTE abXORTable[32] =
{
102, 30, 0, 0, 0, 0, 0, 0,
188, 44, 0, 0, 0, 0, 0, 0,
39, 201, 0, 0, 0, 0, 0, 0,
43, 5, 0, 0, 0, 0, 0, 0,
};
bProcPiece = (bProcPiece ^ abXORTable[m_bCRCMagicCubeIdx]);
bFilePiece = (bFilePiece ^ abXORTable[m_bCRCMagicCubeIdx+1]);
m_dwProcCRC |= bProcPiece << m_bCRCMagicCubeIdx;
m_dwFileCRC |= bFilePiece << m_bCRCMagicCubeIdx;
m_bCRCMagicCubeIdx += 8;
if (!(m_bCRCMagicCubeIdx & 31))
{
m_dwProcCRC = 0;
m_dwFileCRC = 0;
m_bCRCMagicCubeIdx = 0;
}
}
void DESC::SetBillingExpireSecond(DWORD dwSec)
{
m_dwBillingExpireSecond = dwSec;
}
DWORD DESC::GetBillingExpireSecond()
{
return m_dwBillingExpireSecond;
}
void DESC::push_seq(BYTE hdr, BYTE seq)
{
if (m_seq_vector.size()>=20)
{
m_seq_vector.erase(m_seq_vector.begin());
}
seq_t info = { hdr, seq };
m_seq_vector.push_back(info);
}
BYTE DESC::GetEmpire()
{
return m_accountTable.bEmpire;
}
void DESC::ChatPacket(BYTE type, const char * format, ...)
{
char chatbuf[CHAT_MAX_LEN + 1];
va_list args;
va_start(args, format);
int len = vsnprintf(chatbuf, sizeof(chatbuf), format, args);
va_end(args);
struct packet_chat pack_chat;
pack_chat.header = HEADER_GC_CHAT;
pack_chat.size = sizeof(struct packet_chat) + len;
pack_chat.type = type;
pack_chat.id = 0;
pack_chat.bEmpire = GetEmpire();
TEMP_BUFFER buf;
buf.write(&pack_chat, sizeof(struct packet_chat));
buf.write(chatbuf, len);
Packet(buf.read_peek(), buf.size());
}
