Networking Overhaul: Modern packets, buffers, handshake, dispatch & security hardening

See Readme
This commit is contained in:
rtw1x1
2026-02-08 07:36:07 +00:00
parent 058589ca1b
commit cda1c73bd3
72 changed files with 3612 additions and 6155 deletions

View File

@@ -374,61 +374,14 @@ D3DXVECTOR3 CPlaneCollisionInstance::OnGetCollisionMovementAdjust(const CDynamic
const auto vv = (s.v3Position - m_attribute.v3Position);
float t= - D3DXVec3Dot(&m_attribute.v3Normal, &vv)/d;
//D3DXVECTOR3 onplane = s.v3Position+t*advance;
if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
{
//return m_attribute.v3Normal*((-s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
return t*advance -s.fRadius*m_attribute.v3Normal;
}
else
{
//return m_attribute.v3Normal*((s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
return t*advance +s.fRadius*m_attribute.v3Normal;
}
/*if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
{
Tracef("%f %f\n",s.fRadius,-(D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position))));
return m_attribute.v3Normal*((-s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
}
else
{
Tracef("%f %f\n",(s.fRadius),(D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position))));
return m_attribute.v3Normal*((s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
}*/
/*
D3DXVECTOR3 advance = s.v3Position-s.v3LastPosition;
D3DXVECTOR3 slide(-advance.y,advance.x,advance.z);
slide = m_attribute.v3Normal;
D3DXVECTOR3 radius_adjust = advance;
D3DXVec3Normalize(&radius_adjust,&radius_adjust);
radius_adjust*=s.fRadius;
float d = D3DXVec3Dot(&m_attribute.v3Normal, &slide);
if (d>=-0.0001 && d<=0.0001)
return D3DXVECTOR3(0.0f,0.0f,0.0f);
float t= - D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position+radius_adjust-m_attribute.v3Position))
/ d;*/
//D3DXVECTOR3 nextposition;
//nextposition = s.v3Position + t*slide;
//Tracef("$T %f",t);
//if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
// return (t*slide - m_attribute.v3Normal * s.fRadius)/**gc_fReduceMove*/;
//else
// return (t*slide + m_attribute.v3Normal * s.fRadius)/*gc_fReduceMove*/;
//if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
// return (t*slide + m_attribute.v3Normal * D3DXVec3Dot(&m_attribute.v3Normal,&(s.v3LastPosition-m_attribute.v3Position))/** s.fRadius*/)*gc_fReduceMove;
//else
// return (t*slide + m_attribute.v3Normal * D3DXVec3Dot(&m_attribute.v3Normal,&(s.v3LastPosition-m_attribute.v3Position))/*s.fRadius*/)*gc_fReduceMove;
//
}
void CPlaneCollisionInstance::Render(D3DFILLMODE /*d3dFillMode*/)
@@ -462,12 +415,6 @@ bool CCylinderCollisionInstance::CollideCylinderVSDynamicSphere(const TCylinderD
if (s.v3Position.z - s.fRadius > c_rattribute.v3Position.z + c_rattribute.fHeight)
return false;
/*D3DXVECTOR2 v2curDistance(s.v3Position.x - c_rattribute.v3Position.x, s.v3Position.y - c_rattribute.v3Position.y);
float fDistance = D3DXVec2Length(&v2curDistance);
if (fDistance <= s.fRadius + c_rattribute.fRadius)
return true;
*/
D3DXVECTOR3 oa, ob;
IntersectLineSegments(c_rattribute.v3Position, D3DXVECTOR3(c_rattribute.v3Position.x,c_rattribute.v3Position.y,c_rattribute.v3Position.z+c_rattribute.fHeight), s.v3LastPosition, s.v3Position, oa, ob);
const auto vv = (oa - ob);
@@ -671,32 +618,6 @@ bool CAABBCollisionInstance::OnCollisionDynamicSphere(const CDynamicSphereInstan
D3DXVECTOR3 CAABBCollisionInstance::OnGetCollisionMovementAdjust(const CDynamicSphereInstance & s) const
{
//Tracef("OnGetCollisionMovementAdjust v3Min.x = %f, v3Max.x = %f\n", m_attribute.v3Min.x, m_attribute.v3Max.x);
/*
float fARadius = D3DXVec3Length(&(m_attribute.v3Min - m_attribute.v3Max));
if (D3DXVec3LengthSq(&(s.v3Position-(m_attribute.v3Max + m_attribute.v3Min)))>=(s.fRadius+fARadius)*(fARadius+s.fRadius))
return D3DXVECTOR3(0.0f,0.0f,0.0f);
D3DXVECTOR3 c;
D3DXVec3Cross(&c, &(s.v3Position-s.v3LastPosition), &D3DXVECTOR3(0.0f,0.0f,1.0f) );
float sum = - D3DXVec3Dot(&c,&(s.v3Position-(m_attribute.v3Max + m_attribute.v3Min)));
float mul = (s.fRadius+fARadius)*(s.fRadius+fARadius)-D3DXVec3LengthSq(&(s.v3Position-(m_attribute.v3Max + m_attribute.v3Min)));
if (sum*sum-4*mul<=0)
return D3DXVECTOR3(0.0f,0.0f,0.0f);
float sq = sqrt(sum*sum-4*mul);
float t1=-sum-sq, t2=-sum+sq;
t1*=0.5f;
t2*=0.5f;
if (fabs(t1)<=fabs(t2))
{
return (gc_fReduceMove*t1)*c;
}
else
return (gc_fReduceMove*t2)*c;
*/
D3DXVECTOR3 v3Temp;
if(s.v3Position.x + s.fRadius <= m_attribute.v3Min.x) { v3Temp.x = m_attribute.v3Min.x; }
else if(s.v3Position.x - s.fRadius >= m_attribute.v3Max.x) { v3Temp.x = m_attribute.v3Max.x; }

View File

@@ -0,0 +1,73 @@
#pragma once
// Control-plane packet structs used by all CNetworkStream subclasses.
// Extracted from UserInterface/Packet.h so the base class (EterLib)
// can handle key exchange, ping/pong, and phase transitions without
// depending on UserInterface.
#include <cstdint>
// Control-plane header constants (subset of CG::/GC:: namespaces).
// The full CG/GC namespaces live in Packet.h which includes this file,
// so all existing code sees these via Packet.h as before.
namespace CG
{
constexpr uint16_t PONG = 0x0006;
constexpr uint16_t KEY_RESPONSE = 0x000A;
}
namespace GC
{
constexpr uint16_t PING = 0x0007;
constexpr uint16_t PHASE = 0x0008;
constexpr uint16_t KEY_CHALLENGE = 0x000B;
constexpr uint16_t KEY_COMPLETE = 0x000C;
}
#pragma pack(push, 1)
struct TPacketGCPhase
{
uint16_t header;
uint16_t length;
uint8_t phase;
};
struct TPacketGCPing
{
uint16_t header;
uint16_t length;
uint32_t server_time;
};
struct TPacketCGPong
{
uint16_t header;
uint16_t length;
};
struct TPacketGCKeyChallenge
{
uint16_t header;
uint16_t length;
uint8_t server_pk[32];
uint8_t challenge[32];
uint32_t server_time;
};
struct TPacketCGKeyResponse
{
uint16_t header;
uint16_t length;
uint8_t client_pk[32];
uint8_t challenge_response[32];
};
struct TPacketGCKeyComplete
{
uint16_t header;
uint16_t length;
uint8_t encrypted_token[32 + 16];
uint8_t nonce[24];
};
#pragma pack(pop)

View File

@@ -240,48 +240,3 @@ void CDecal::Render()
sizeof(TPDTVertex));
}
/*
//////////////////////////////////////////////////////////////////////////
// CDecalManager
//////////////////////////////////////////////////////////////////////////
CDecalManager aDecalManager;
CDecalManager::CDecalManager()
{
m_DecalPtrVector.clear();
}
CDecalManager::~CDecalManager()
{
m_DecalPtrVector.clear();
}
void CDecalManager::Add(CDecal * pDecal)
{
m_DecalPtrVector.push_back(pDecal);
}
void CDecalManager::Remove(CDecal * pDecal)
{
std::vector<CDecal *>::iterator aIterator;
for (aIterator = m_DecalPtrVector.begin(); aIterator != m_DecalPtrVector.end();)
{
if (*aIterator == pDecal)
aIterator = m_DecalPtrVector.erase(aIterator);
else
++aIterator;
}
}
void CDecalManager::Update()
{
for (DWORD dwi = 0; dwi < m_DecalPtrVector.size(); ++dwi)
m_DecalPtrVector[dwi]->Update();
}
void CDecalManager::Render()
{
for (DWORD dwi = 0; dwi < m_DecalPtrVector.size(); ++dwi)
m_DecalPtrVector[dwi]->Render();
}
*/

View File

@@ -1,99 +0,0 @@
#include "StdAfx.h"
#include "NetDatagram.h"
CNetworkDatagram::CNetworkDatagram()
{
__Initialize();
}
CNetworkDatagram::~CNetworkDatagram()
{
Destroy();
}
void CNetworkDatagram::Destroy()
{
if (INVALID_SOCKET==m_sock)
return;
closesocket(m_sock);
__Initialize();
}
bool CNetworkDatagram::Create(UINT uPort)
{
assert(INVALID_SOCKET==m_sock);
m_sock = socket(AF_INET, SOCK_DGRAM, 0);
DWORD arg = 1;
ioctlsocket(m_sock, FIONBIO, &arg); // Non-blocking mode
SOCKADDR_IN sockAddrIn;
memset(&sockAddrIn, 0, sizeof(SOCKADDR_IN));
sockAddrIn.sin_family = AF_INET;
sockAddrIn.sin_addr.s_addr = INADDR_ANY;
sockAddrIn.sin_port = htons(uPort);
if (SOCKET_ERROR == bind(m_sock, (PSOCKADDR)&sockAddrIn, sizeof(SOCKADDR_IN)))
{
return false;
}
return true;
}
#pragma warning(push)
#pragma warning(disable:4127)
void CNetworkDatagram::Update()
{
if (m_sock == INVALID_SOCKET)
return;
FD_ZERO(&m_fdsRecv);
FD_ZERO(&m_fdsSend);
FD_SET(m_sock, &m_fdsRecv);
FD_SET(m_sock, &m_fdsSend);
TIMEVAL delay;
delay.tv_sec = 0;
delay.tv_usec = 0;
if (select(0, &m_fdsRecv, &m_fdsSend, NULL, &delay) == SOCKET_ERROR)
return;
}
#pragma warning(pop)
bool CNetworkDatagram::CanRecv()
{
if (FD_ISSET(m_sock, &m_fdsRecv))
return true;
return false;
}
int CNetworkDatagram::PeekRecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn)
{
int nSockAddrInLen=sizeof(SOCKADDR_IN);
return recvfrom(m_sock, (char*)pvBuf, uBufLen, MSG_PEEK, (PSOCKADDR)pkSockAddrIn, &nSockAddrInLen);
}
int CNetworkDatagram::RecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn)
{
int nSockAddrInLen=sizeof(SOCKADDR_IN);
return recvfrom(m_sock, (char*)pvBuf, uBufLen, 0, (PSOCKADDR)pkSockAddrIn, &nSockAddrInLen);
}
int CNetworkDatagram::SendTo(UINT uBufLen, const void* c_pvBuf, const SOCKADDR_IN& c_rkSockAddrIn)
{
return sendto(m_sock, (const char *)c_pvBuf, uBufLen, 0, (PSOCKADDR)&c_rkSockAddrIn, sizeof(SOCKADDR_IN));
}
void CNetworkDatagram::__Initialize()
{
m_sock=INVALID_SOCKET;
}

View File

@@ -1,28 +0,0 @@
#pragma once
class CNetworkDatagram
{
public:
CNetworkDatagram();
virtual ~CNetworkDatagram();
void Destroy();
bool Create(UINT uPort);
void Update();
bool CanRecv();
int PeekRecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn);
int RecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn);
int SendTo(UINT uBufLen, const void* c_pvBuf, const SOCKADDR_IN& c_rkSockAddrIn);
private:
void __Initialize();
private:
SOCKET m_sock;
fd_set m_fdsRecv;
fd_set m_fdsSend;
};

View File

@@ -1,105 +0,0 @@
#include "StdAfx.h"
#include "NetDatagramReceiver.h"
BOOL CNetDatagramReceiver::Process()
{
m_recvBufCurrentPos = 0;
m_recvBufCurrentSize = 0;
int irecvAddrLength = sizeof(SOCKADDR_IN);
m_recvBufCurrentSize = recvfrom(m_Socket, (char *)m_recvBuf, m_recvBufSize, 0, (PSOCKADDR)&m_SockAddr, &irecvAddrLength);
if (m_recvBufCurrentSize <= 0)
{
return FALSE;
}
return TRUE;
}
BOOL CNetDatagramReceiver::Recv(void * pBuffer, int iSize)
{
if (!Peek(pBuffer, iSize))
return FALSE;
m_recvBufCurrentPos += iSize;
return TRUE;
}
BOOL CNetDatagramReceiver::Peek(void * pBuffer, int iSize)
{
if (m_recvBufCurrentSize < m_recvBufCurrentPos+iSize)
return FALSE;
memcpy(pBuffer, m_recvBuf + m_recvBufCurrentPos, iSize);
return TRUE;
}
BOOL CNetDatagramReceiver::isBind()
{
return m_isBind;
}
BOOL CNetDatagramReceiver::Bind(DWORD /*dwAddress*/, WORD wPortIndex)
{
m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
DWORD arg = 1;
ioctlsocket(m_Socket, FIONBIO, &arg); // Non-blocking mode
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
m_SockAddr.sin_family = AF_INET;
// m_SockAddr.sin_addr.s_addr = dwAddress;
m_SockAddr.sin_addr.s_addr = INADDR_ANY;
m_SockAddr.sin_port = htons(wPortIndex);
if (bind(m_Socket, (PSOCKADDR)&m_SockAddr, sizeof(SOCKADDR_IN)) < 0)
{
Tracef("Failed binding socket\n");
return FALSE;
}
m_isBind = TRUE;
return TRUE;
}
void CNetDatagramReceiver::SetRecvBufferSize(int recvBufSize)
{
if (m_recvBuf)
{
if (m_recvBufSize>recvBufSize)
return;
delete [] m_recvBuf;
}
m_recvBufSize=recvBufSize;
m_recvBuf=new char[m_recvBufSize];
}
void CNetDatagramReceiver::Clear()
{
m_isBind = FALSE;
m_dwPortIndex = 1000;
m_Socket = 0;
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
m_recvBufCurrentPos = 0;
m_recvBufCurrentSize = 0;
}
CNetDatagramReceiver::CNetDatagramReceiver()
{
m_recvBuf = NULL;
m_recvBufSize = 0;
Clear();
}
CNetDatagramReceiver::~CNetDatagramReceiver()
{
if (m_recvBuf)
delete [] m_recvBuf;
}

View File

@@ -1,36 +0,0 @@
#pragma once
#ifndef VC_EXTRALEAN
class CNetDatagramReceiver
{
public:
CNetDatagramReceiver();
virtual ~CNetDatagramReceiver();
void Clear();
BOOL Bind(DWORD dwAddress, WORD wPortIndex);
BOOL isBind();
BOOL Process();
BOOL Recv(void * pBuffer, int iSize);
BOOL Peek(void * pBuffer, int iSize);
void SetRecvBufferSize(int recvBufSize);
protected:
BOOL m_isBind;
DWORD m_dwPortIndex;
SOCKET m_Socket;
SOCKADDR_IN m_SockAddr;
int m_recvBufCurrentPos;
int m_recvBufCurrentSize;
char* m_recvBuf;
int m_recvBufSize;
};
#endif

View File

@@ -1,58 +0,0 @@
#include "StdAfx.h"
#include "NetDatagramSender.h"
BOOL CNetDatagramSender::SetSocket(const char * c_szIP, WORD wPortIndex)
{
return SetSocket(inet_addr(c_szIP), wPortIndex);
}
BOOL CNetDatagramSender::SetSocket(DWORD dwAddress, WORD wPortIndex)
{
m_isSocket = TRUE;
m_dwAddress = dwAddress;
m_wPortIndex = wPortIndex;
m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
m_SockAddr.sin_family = AF_INET;
m_SockAddr.sin_addr.s_addr = dwAddress;
m_SockAddr.sin_port = htons(wPortIndex);
return TRUE;
}
BOOL CNetDatagramSender::Send(const void * pBuffer, int iSize)
{
assert(isSocket());
int iSendingLength = sendto(m_Socket, (const char *)pBuffer, iSize, 0, (PSOCKADDR)&m_SockAddr, sizeof(SOCKADDR_IN));
if (iSendingLength < 0)
{
Tracef("Failed sending packet\n");
return FALSE;
}
return TRUE;
}
BOOL CNetDatagramSender::isSocket()
{
return m_isSocket;
}
CNetDatagramSender::CNetDatagramSender()
{
m_isSocket = FALSE;
m_dwAddress = 0;
m_wPortIndex = 1000;
m_Socket = 0;
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
}
CNetDatagramSender::~CNetDatagramSender()
{
}

View File

@@ -1,27 +0,0 @@
#pragma once
#ifndef VC_EXTRALEAN
class CNetDatagramSender
{
public:
CNetDatagramSender();
virtual ~CNetDatagramSender();
BOOL isSocket();
BOOL SetSocket(const char * c_szIP, WORD wPortIndex);
BOOL SetSocket(DWORD dwAddress, WORD wPortIndex);
BOOL Send(const void * pBuffer, int iSize);
protected:
BOOL m_isSocket;
WORD m_dwAddress;
WORD m_wPortIndex;
SOCKET m_Socket;
SOCKADDR_IN m_SockAddr;
};
#endif

View File

@@ -7,14 +7,12 @@ class CNetworkPacketHeaderMap
public:
typedef struct SPacketType
{
SPacketType(int iSize = 0, bool bFlag = false)
SPacketType(int iSize = 0)
: iPacketSize(iSize)
{
iPacketSize = iSize;
isDynamicSizePacket = bFlag;
}
int iPacketSize;
bool isDynamicSizePacket;
int iPacketSize; // Expected/minimum packet size (actual size from wire length field)
} TPacketType;
public:

View File

@@ -7,6 +7,11 @@
#define _PACKETDUMP
#endif
#ifdef _PACKETDUMP
#include <unordered_map>
#include "../UserInterface/Packet.h"
#endif
bool CNetworkStream::IsSecurityMode()
{
return m_secureCipher.IsActivated();
@@ -14,58 +19,29 @@ bool CNetworkStream::IsSecurityMode()
void CNetworkStream::DecryptPendingRecvData()
{
int remaining = m_recvBufInputPos - m_recvBufOutputPos;
size_t remaining = m_recvBuf.ReadableBytes();
if (remaining > 0 && m_secureCipher.IsActivated())
{
m_secureCipher.DecryptInPlace(m_recvBuf + m_recvBufOutputPos, remaining);
}
m_secureCipher.DecryptInPlace(m_recvBuf.DataAt(m_recvBuf.ReadPos()), remaining);
}
void CNetworkStream::SetRecvBufferSize(int recvBufSize)
{
if (m_recvBuf)
{
if (m_recvBufSize > recvBufSize)
return;
delete [] m_recvBuf;
}
m_recvBufSize = recvBufSize;
m_recvBuf = new char[m_recvBufSize];
m_recvBuf.Reserve(static_cast<size_t>(recvBufSize));
}
void CNetworkStream::SetSendBufferSize(int sendBufSize)
{
if (m_sendBuf)
{
if (m_sendBufSize > sendBufSize)
return;
delete [] m_sendBuf;
}
m_sendBufSize = sendBufSize;
m_sendBuf = new char[m_sendBufSize];
m_sendBuf.Reserve(static_cast<size_t>(sendBufSize));
}
bool CNetworkStream::__RecvInternalBuffer()
{
if (m_recvBufOutputPos > 0)
{
int recvBufDataSize = m_recvBufInputPos - m_recvBufOutputPos;
if (recvBufDataSize > 0)
{
memmove(m_recvBuf, m_recvBuf + m_recvBufOutputPos, recvBufDataSize);
}
m_recvBuf.EnsureWritable(4096);
m_recvBufInputPos -= m_recvBufOutputPos;
m_recvBufOutputPos = 0;
}
int restSize = m_recvBufSize - m_recvBufInputPos;
int restSize = static_cast<int>(m_recvBuf.WritableBytes());
if (restSize > 0)
{
int recvSize = recv(m_sock, m_recvBuf + m_recvBufInputPos, restSize, 0);
int recvSize = recv(m_sock, reinterpret_cast<char*>(m_recvBuf.WritePtr()), restSize, 0);
if (recvSize < 0)
{
@@ -80,47 +56,33 @@ bool CNetworkStream::__RecvInternalBuffer()
else
{
if (m_secureCipher.IsActivated())
{
m_secureCipher.DecryptInPlace(m_recvBuf + m_recvBufInputPos, recvSize);
}
m_recvBufInputPos += recvSize;
m_secureCipher.DecryptInPlace(m_recvBuf.WritePtr(), recvSize);
m_recvBuf.CommitWrite(recvSize);
}
}
return true;
}
bool CNetworkStream::__SendInternalBuffer()
{
int dataSize = __GetSendBufferSize();
if (dataSize <= 0)
return true;
int sendSize = send(m_sock, m_sendBuf + m_sendBufOutputPos, dataSize, 0);
int sendSize = send(m_sock, reinterpret_cast<const char*>(m_sendBuf.ReadPtr()), dataSize, 0);
if (sendSize < 0)
return false;
m_sendBufOutputPos += sendSize;
__PopSendBuffer();
return true;
}
void CNetworkStream::__PopSendBuffer()
{
if (m_sendBufOutputPos <= 0)
return;
int sendBufDataSize = m_sendBufInputPos - m_sendBufOutputPos;
if (sendBufDataSize > 0)
{
memmove(m_sendBuf, m_sendBuf + m_sendBufOutputPos, sendBufDataSize);
int err = WSAGetLastError();
TraceError("__SendInternalBuffer: send() failed, sock=%llu, dataSize=%d, error=%d",
(unsigned long long)m_sock, dataSize, err);
return false;
}
m_sendBufInputPos = sendBufDataSize;
m_sendBufOutputPos = 0;
m_sendBuf.Discard(sendSize);
return true;
}
#pragma warning(push)
@@ -163,7 +125,7 @@ void CNetworkStream::Process()
return;
}
if (FD_ISSET(m_sock, &fdsSend) && (m_sendBufInputPos > m_sendBufOutputPos))
if (FD_ISSET(m_sock, &fdsSend) && (m_sendBuf.ReadableBytes() > 0))
{
if (!__SendInternalBuffer())
{
@@ -206,24 +168,20 @@ void CNetworkStream::Disconnect()
void CNetworkStream::Clear()
{
if (m_sock == INVALID_SOCKET)
return;
// Always clean cipher state (erase key material promptly)
m_secureCipher.CleanUp();
closesocket(m_sock);
m_sock = INVALID_SOCKET;
if (m_sock != INVALID_SOCKET)
{
closesocket(m_sock);
m_sock = INVALID_SOCKET;
}
m_isOnline = false;
m_connectLimitTime = 0;
m_recvBufInputPos = 0;
m_recvBufOutputPos = 0;
m_sendBufInputPos = 0;
m_sendBufOutputPos = 0;
m_SequenceGenerator.seed(SEQUENCE_SEED);
m_recvBuf.Clear();
m_sendBuf.Clear();
}
bool CNetworkStream::Connect(const CNetworkAddress& c_rkNetAddr, int limitSec)
@@ -294,251 +252,229 @@ bool CNetworkStream::Connect(const char* c_szAddr, int port, int /*limitSec*/)
void CNetworkStream::ClearRecvBuffer()
{
m_recvBufOutputPos = m_recvBufInputPos = 0;
m_recvBuf.Clear();
}
int CNetworkStream::GetRecvBufferSize()
{
return m_recvBufInputPos - m_recvBufOutputPos;
return static_cast<int>(m_recvBuf.ReadableBytes());
}
bool CNetworkStream::Peek(int size)
{
if (GetRecvBufferSize() < size)
return false;
return true;
return m_recvBuf.HasBytes(static_cast<size_t>(size));
}
bool CNetworkStream::Peek(int size, char * pDestBuf)
bool CNetworkStream::Peek(int size, char* pDestBuf)
{
if (GetRecvBufferSize() < size)
return false;
memcpy(pDestBuf, m_recvBuf + m_recvBufOutputPos, size);
return true;
return m_recvBuf.Peek(pDestBuf, static_cast<size_t>(size));
}
#ifdef _PACKETDUMP
const char * GetSendHeaderName(BYTE header)
static const char* GetHeaderName(uint16_t header)
{
static bool b = false;
static std::string stringList[UCHAR_MAX+1];
if (b==false)
{
for (DWORD i = 0; i < UCHAR_MAX+1; i++)
{
char buf[10];
sprintf(buf,"%d",i);
stringList[i] = buf;
}
stringList[2] = "HEADER_CG_ATTACK";
stringList[3] = "HEADER_CG_CHAT";
stringList[4] = "HEADER_CG_PLAYER_CREATE";
stringList[5] = "HEADER_CG_PLAYER_DESTROY";
stringList[6] = "HEADER_CG_PLAYER_SELECT";
stringList[7] = "HEADER_CG_CHARACTER_MOVE";
stringList[8] = "HEADER_CG_SYNC_POSITION";
stringList[9] = "HEADER_CG_DIRECT_ENTER";
stringList[10] = "HEADER_CG_ENTERGAME";
stringList[11] = "HEADER_CG_ITEM_USE";
stringList[12] = "HEADER_CG_ITEM_DROP";
stringList[13] = "HEADER_CG_ITEM_MOVE";
stringList[15] = "HEADER_CG_ITEM_PICKUP";
stringList[16] = "HEADER_CG_QUICKSLOT_ADD";
stringList[17] = "HEADER_CG_QUICKSLOT_DEL";
stringList[18] = "HEADER_CG_QUICKSLOT_SWAP";
stringList[19] = "HEADER_CG_WHISPER";
stringList[20] = "HEADER_CG_ITEM_DROP2";
stringList[26] = "HEADER_CG_ON_CLICK";
stringList[27] = "HEADER_CG_EXCHANGE";
stringList[28] = "HEADER_CG_CHARACTER_POSITION";
stringList[29] = "HEADER_CG_SCRIPT_ANSWER";
stringList[30] = "HEADER_CG_QUEST_INPUT_STRING";
stringList[31] = "HEADER_CG_QUEST_CONFIRM";
stringList[41] = "HEADER_CG_PVP";
stringList[50] = "HEADER_CG_SHOP";
stringList[51] = "HEADER_CG_FLY_TARGETING";
stringList[52] = "HEADER_CG_USE_SKILL";
stringList[53] = "HEADER_CG_ADD_FLY_TARGETING";
stringList[54] = "HEADER_CG_SHOOT";
stringList[55] = "HEADER_CG_MYSHOP";
stringList[60] = "HEADER_CG_ITEM_USE_TO_ITEM";
stringList[61] = "HEADER_CG_TARGET";
stringList[65] = "HEADER_CG_WARP";
stringList[66] = "HEADER_CG_SCRIPT_BUTTON";
stringList[67] = "HEADER_CG_MESSENGER";
stringList[69] = "HEADER_CG_MALL_CHECKOUT";
stringList[70] = "HEADER_CG_SAFEBOX_CHECKIN";
stringList[71] = "HEADER_CG_SAFEBOX_CHECKOUT";
stringList[72] = "HEADER_CG_PARTY_INVITE";
stringList[73] = "HEADER_CG_PARTY_INVITE_ANSWER";
stringList[74] = "HEADER_CG_PARTY_REMOVE";
stringList[75] = "HEADER_CG_PARTY_SET_STATE";
stringList[76] = "HEADER_CG_PARTY_USE_SKILL";
stringList[77] = "HEADER_CG_SAFEBOX_ITEM_MOVE";
stringList[78] = "HEADER_CG_PARTY_PARAMETER";
stringList[80] = "HEADER_CG_GUILD";
stringList[81] = "HEADER_CG_ANSWER_MAKE_GUILD";
stringList[82] = "HEADER_CG_FISHING";
stringList[83] = "HEADER_CG_GIVE_ITEM";
stringList[90] = "HEADER_CG_EMPIRE";
stringList[96] = "HEADER_CG_REFINE";
stringList[100] = "HEADER_CG_MARK_LOGIN";
stringList[101] = "HEADER_CG_MARK_CRCLIST";
stringList[102] = "HEADER_CG_MARK_UPLOAD";
stringList[103] = "HEADER_CG_CRC_REPORT";
stringList[105] = "HEADER_CG_HACK";
stringList[106] = "HEADER_CG_CHANGE_NAME";
stringList[107] = "HEADER_CG_SMS";
stringList[108] = "HEADER_CG_MATRIX_CARD";
stringList[109] = "HEADER_CG_LOGIN2";
stringList[110] = "HEADER_CG_DUNGEON";
stringList[111] = "HEADER_CG_LOGIN3";
stringList[112] = "HEADER_CG_GUILD_SYMBOL_UPLOAD";
stringList[113] = "HEADER_CG_GUILD_SYMBOL_CRC";
stringList[114] = "HEADER_CG_SCRIPT_SELECT_ITEM";
stringList[0xf9] = "HEADER_CG_KEY_RESPONSE";
stringList[0xfc] = "HEADER_CG_TIME_SYNC";
stringList[0xfd] = "HEADER_CG_CLIENT_VERSION";
stringList[0xfe] = "HEADER_CG_PONG";
stringList[0xff] = "HEADER_CG_HANDSHAKE";
}
return stringList[header].c_str();
}
static const std::unordered_map<uint16_t, const char*> s_headerNames = {
// Control
{ CG::PONG, "CG_PONG" },
{ GC::PING, "GC_PING" },
{ GC::PHASE, "GC_PHASE" },
{ CG::KEY_RESPONSE, "CG_KEY_RESPONSE" },
{ GC::KEY_CHALLENGE, "GC_KEY_CHALLENGE" },
{ GC::KEY_COMPLETE, "GC_KEY_COMPLETE" },
{ CG::CLIENT_VERSION, "CG_CLIENT_VERSION" },
{ CG::STATE_CHECKER, "CG_STATE_CHECKER" },
{ GC::RESPOND_CHANNELSTATUS, "GC_RESPOND_CHANNELSTATUS" },
{ CG::TEXT, "CG_TEXT" },
// Authentication
{ CG::LOGIN2, "CG_LOGIN2" },
{ CG::LOGIN3, "CG_LOGIN3" },
{ CG::LOGIN_SECURE, "CG_LOGIN_SECURE" },
{ GC::LOGIN_SUCCESS3, "GC_LOGIN_SUCCESS3" },
{ GC::LOGIN_SUCCESS4, "GC_LOGIN_SUCCESS4" },
{ GC::LOGIN_FAILURE, "GC_LOGIN_FAILURE" },
{ GC::LOGIN_KEY, "GC_LOGIN_KEY" },
{ GC::AUTH_SUCCESS, "GC_AUTH_SUCCESS" },
{ GC::EMPIRE, "GC_EMPIRE" },
{ CG::EMPIRE, "CG_EMPIRE" },
{ CG::CHANGE_NAME, "CG_CHANGE_NAME" },
{ GC::CHANGE_NAME, "GC_CHANGE_NAME" },
// Character
{ CG::CHARACTER_CREATE, "CG_CHARACTER_CREATE" },
{ CG::CHARACTER_DELETE, "CG_CHARACTER_DELETE" },
{ CG::CHARACTER_SELECT, "CG_CHARACTER_SELECT" },
{ CG::ENTERGAME, "CG_ENTERGAME" },
{ GC::CHARACTER_ADD, "GC_CHARACTER_ADD" },
{ GC::CHARACTER_ADD2, "GC_CHARACTER_ADD2" },
{ GC::CHAR_ADDITIONAL_INFO, "GC_CHAR_ADDITIONAL_INFO" },
{ GC::CHARACTER_DEL, "GC_CHARACTER_DEL" },
{ GC::CHARACTER_UPDATE, "GC_CHARACTER_UPDATE" },
{ GC::CHARACTER_UPDATE2, "GC_CHARACTER_UPDATE2" },
{ GC::CHARACTER_POSITION, "GC_CHARACTER_POSITION" },
{ GC::PLAYER_CREATE_SUCCESS, "GC_PLAYER_CREATE_SUCCESS" },
{ GC::PLAYER_CREATE_FAILURE, "GC_PLAYER_CREATE_FAILURE" },
{ GC::PLAYER_DELETE_SUCCESS, "GC_PLAYER_DELETE_SUCCESS" },
{ GC::PLAYER_DELETE_WRONG_SOCIAL_ID, "GC_PLAYER_DELETE_WRONG_SOCIAL_ID" },
{ GC::MAIN_CHARACTER, "GC_MAIN_CHARACTER" },
{ GC::PLAYER_POINTS, "GC_PLAYER_POINTS" },
{ GC::PLAYER_POINT_CHANGE, "GC_PLAYER_POINT_CHANGE" },
{ GC::STUN, "GC_STUN" },
{ GC::DEAD, "GC_DEAD" },
{ GC::CHANGE_SPEED, "GC_CHANGE_SPEED" },
{ GC::WALK_MODE, "GC_WALK_MODE" },
{ GC::SKILL_LEVEL, "GC_SKILL_LEVEL" },
{ GC::SKILL_LEVEL_NEW, "GC_SKILL_LEVEL_NEW" },
{ GC::SKILL_COOLTIME_END, "GC_SKILL_COOLTIME_END" },
{ GC::CHANGE_SKILL_GROUP, "GC_CHANGE_SKILL_GROUP" },
{ GC::VIEW_EQUIP, "GC_VIEW_EQUIP" },
// Movement
{ CG::MOVE, "CG_MOVE" },
{ GC::MOVE, "GC_MOVE" },
{ CG::SYNC_POSITION, "CG_SYNC_POSITION" },
{ GC::SYNC_POSITION, "GC_SYNC_POSITION" },
{ CG::WARP, "CG_WARP" },
{ GC::WARP, "GC_WARP" },
{ GC::MOTION, "GC_MOTION" },
{ GC::DIG_MOTION, "GC_DIG_MOTION" },
// Combat
{ CG::ATTACK, "CG_ATTACK" },
{ CG::USE_SKILL, "CG_USE_SKILL" },
{ CG::SHOOT, "CG_SHOOT" },
{ CG::FLY_TARGETING, "CG_FLY_TARGETING" },
{ CG::ADD_FLY_TARGETING, "CG_ADD_FLY_TARGETING" },
{ GC::DAMAGE_INFO, "GC_DAMAGE_INFO" },
{ GC::FLY_TARGETING, "GC_FLY_TARGETING" },
{ GC::ADD_FLY_TARGETING, "GC_ADD_FLY_TARGETING" },
{ GC::CREATE_FLY, "GC_CREATE_FLY" },
{ GC::PVP, "GC_PVP" },
{ GC::DUEL_START, "GC_DUEL_START" },
// Items
{ CG::ITEM_USE, "CG_ITEM_USE" },
{ CG::ITEM_DROP, "CG_ITEM_DROP" },
{ CG::ITEM_DROP2, "CG_ITEM_DROP2" },
{ CG::ITEM_MOVE, "CG_ITEM_MOVE" },
{ CG::ITEM_PICKUP, "CG_ITEM_PICKUP" },
{ CG::ITEM_USE_TO_ITEM, "CG_ITEM_USE_TO_ITEM" },
{ CG::ITEM_GIVE, "CG_ITEM_GIVE" },
{ CG::EXCHANGE, "CG_EXCHANGE" },
{ CG::QUICKSLOT_ADD, "CG_QUICKSLOT_ADD" },
{ CG::QUICKSLOT_DEL, "CG_QUICKSLOT_DEL" },
{ CG::QUICKSLOT_SWAP, "CG_QUICKSLOT_SWAP" },
{ CG::REFINE, "CG_REFINE" },
{ CG::DRAGON_SOUL_REFINE, "CG_DRAGON_SOUL_REFINE" },
{ GC::ITEM_DEL, "GC_ITEM_DEL" },
{ GC::ITEM_SET, "GC_ITEM_SET" },
{ GC::ITEM_USE, "GC_ITEM_USE" },
{ GC::ITEM_DROP, "GC_ITEM_DROP" },
{ GC::ITEM_UPDATE, "GC_ITEM_UPDATE" },
{ GC::ITEM_GROUND_ADD, "GC_ITEM_GROUND_ADD" },
{ GC::ITEM_GROUND_DEL, "GC_ITEM_GROUND_DEL" },
{ GC::ITEM_OWNERSHIP, "GC_ITEM_OWNERSHIP" },
{ GC::ITEM_GET, "GC_ITEM_GET" },
{ GC::QUICKSLOT_ADD, "GC_QUICKSLOT_ADD" },
{ GC::QUICKSLOT_DEL, "GC_QUICKSLOT_DEL" },
{ GC::QUICKSLOT_SWAP, "GC_QUICKSLOT_SWAP" },
{ GC::EXCHANGE, "GC_EXCHANGE" },
{ GC::REFINE_INFORMATION, "GC_REFINE_INFORMATION" },
{ GC::DRAGON_SOUL_REFINE, "GC_DRAGON_SOUL_REFINE" },
// Chat
{ CG::CHAT, "CG_CHAT" },
{ CG::WHISPER, "CG_WHISPER" },
{ GC::CHAT, "GC_CHAT" },
{ GC::WHISPER, "GC_WHISPER" },
// Social
{ CG::PARTY_INVITE, "CG_PARTY_INVITE" },
{ CG::PARTY_INVITE_ANSWER, "CG_PARTY_INVITE_ANSWER" },
{ CG::PARTY_REMOVE, "CG_PARTY_REMOVE" },
{ CG::PARTY_SET_STATE, "CG_PARTY_SET_STATE" },
{ CG::PARTY_USE_SKILL, "CG_PARTY_USE_SKILL" },
{ CG::PARTY_PARAMETER, "CG_PARTY_PARAMETER" },
{ GC::PARTY_INVITE, "GC_PARTY_INVITE" },
{ GC::PARTY_ADD, "GC_PARTY_ADD" },
{ GC::PARTY_UPDATE, "GC_PARTY_UPDATE" },
{ GC::PARTY_REMOVE, "GC_PARTY_REMOVE" },
{ GC::PARTY_LINK, "GC_PARTY_LINK" },
{ GC::PARTY_UNLINK, "GC_PARTY_UNLINK" },
{ GC::PARTY_PARAMETER, "GC_PARTY_PARAMETER" },
{ CG::GUILD, "CG_GUILD" },
{ CG::ANSWER_MAKE_GUILD, "CG_ANSWER_MAKE_GUILD" },
{ CG::GUILD_SYMBOL_UPLOAD, "CG_GUILD_SYMBOL_UPLOAD" },
{ CG::SYMBOL_CRC, "CG_SYMBOL_CRC" },
{ GC::GUILD, "GC_GUILD" },
{ GC::REQUEST_MAKE_GUILD, "GC_REQUEST_MAKE_GUILD" },
{ GC::SYMBOL_DATA, "GC_SYMBOL_DATA" },
{ CG::MESSENGER, "CG_MESSENGER" },
{ GC::MESSENGER, "GC_MESSENGER" },
{ GC::LOVER_INFO, "GC_LOVER_INFO" },
{ GC::LOVE_POINT_UPDATE, "GC_LOVE_POINT_UPDATE" },
// Shop / Trade
{ CG::SHOP, "CG_SHOP" },
{ CG::MYSHOP, "CG_MYSHOP" },
{ GC::SHOP, "GC_SHOP" },
{ GC::SHOP_SIGN, "GC_SHOP_SIGN" },
{ CG::SAFEBOX_CHECKIN, "CG_SAFEBOX_CHECKIN" },
{ CG::SAFEBOX_CHECKOUT, "CG_SAFEBOX_CHECKOUT" },
{ CG::SAFEBOX_ITEM_MOVE, "CG_SAFEBOX_ITEM_MOVE" },
{ GC::SAFEBOX_SET, "GC_SAFEBOX_SET" },
{ GC::SAFEBOX_DEL, "GC_SAFEBOX_DEL" },
{ GC::SAFEBOX_WRONG_PASSWORD, "GC_SAFEBOX_WRONG_PASSWORD" },
{ GC::SAFEBOX_SIZE, "GC_SAFEBOX_SIZE" },
{ GC::SAFEBOX_MONEY_CHANGE, "GC_SAFEBOX_MONEY_CHANGE" },
{ CG::MALL_CHECKOUT, "CG_MALL_CHECKOUT" },
{ GC::MALL_OPEN, "GC_MALL_OPEN" },
{ GC::MALL_SET, "GC_MALL_SET" },
{ GC::MALL_DEL, "GC_MALL_DEL" },
// Quest
{ CG::SCRIPT_ANSWER, "CG_SCRIPT_ANSWER" },
{ CG::SCRIPT_BUTTON, "CG_SCRIPT_BUTTON" },
{ CG::SCRIPT_SELECT_ITEM, "CG_SCRIPT_SELECT_ITEM" },
{ CG::QUEST_INPUT_STRING, "CG_QUEST_INPUT_STRING" },
{ CG::QUEST_CONFIRM, "CG_QUEST_CONFIRM" },
{ CG::QUEST_CANCEL, "CG_QUEST_CANCEL" },
{ GC::SCRIPT, "GC_SCRIPT" },
{ GC::QUEST_CONFIRM, "GC_QUEST_CONFIRM" },
{ GC::QUEST_INFO, "GC_QUEST_INFO" },
// UI / Effects
{ CG::TARGET, "CG_TARGET" },
{ CG::ON_CLICK, "CG_ON_CLICK" },
{ GC::TARGET, "GC_TARGET" },
{ GC::TARGET_UPDATE, "GC_TARGET_UPDATE" },
{ GC::TARGET_DELETE, "GC_TARGET_DELETE" },
{ GC::TARGET_CREATE_NEW, "GC_TARGET_CREATE_NEW" },
{ GC::AFFECT_ADD, "GC_AFFECT_ADD" },
{ GC::AFFECT_REMOVE, "GC_AFFECT_REMOVE" },
{ GC::SEPCIAL_EFFECT, "GC_SPECIAL_EFFECT" },
{ GC::SPECIFIC_EFFECT, "GC_SPECIFIC_EFFECT" },
{ GC::MOUNT, "GC_MOUNT" },
{ GC::OWNERSHIP, "GC_OWNERSHIP" },
{ GC::NPC_POSITION, "GC_NPC_POSITION" },
{ CG::CHARACTER_POSITION, "CG_CHARACTER_POSITION" },
// World
{ CG::FISHING, "CG_FISHING" },
{ CG::DUNGEON, "CG_DUNGEON" },
{ CG::HACK, "CG_HACK" },
{ GC::FISHING, "GC_FISHING" },
{ GC::DUNGEON, "GC_DUNGEON" },
{ GC::LAND_LIST, "GC_LAND_LIST" },
{ GC::TIME, "GC_TIME" },
{ GC::CHANNEL, "GC_CHANNEL" },
{ GC::MARK_UPDATE, "GC_MARK_UPDATE" },
// Guild Marks
{ CG::MARK_LOGIN, "CG_MARK_LOGIN" },
{ CG::MARK_CRCLIST, "CG_MARK_CRCLIST" },
{ CG::MARK_UPLOAD, "CG_MARK_UPLOAD" },
{ CG::MARK_IDXLIST, "CG_MARK_IDXLIST" },
{ GC::MARK_BLOCK, "GC_MARK_BLOCK" },
{ GC::MARK_IDXLIST, "GC_MARK_IDXLIST" },
};
const char * GetRecvHeaderName(BYTE header)
{
static bool b = false;
static std::string stringList[UCHAR_MAX+1];
if (b==false)
{
for (DWORD i = 0; i < UCHAR_MAX+1; i++)
{
char buf[10];
sprintf(buf,"%d",i);
stringList[i] = buf;
}
stringList[1] = "HEADER_GC_CHARACTER_ADD";
stringList[2] = "HEADER_GC_CHARACTER_DEL";
stringList[3] = "HEADER_GC_CHARACTER_MOVE";
stringList[4] = "HEADER_GC_CHAT";
stringList[5] = "HEADER_GC_SYNC_POSITION";
stringList[6] = "HEADER_GC_LOGIN_SUCCESS";
stringList[7] = "HEADER_GC_LOGIN_FAILURE";
stringList[8] = "HEADER_GC_PLAYER_CREATE_SUCCESS";
stringList[9] = "HEADER_GC_PLAYER_CREATE_FAILURE";
stringList[10] = "HEADER_GC_PLAYER_DELETE_SUCCESS";
stringList[11] = "HEADER_GC_PLAYER_DELETE_WRONG_SOCIAL_ID";
auto it = s_headerNames.find(header);
if (it != s_headerNames.end())
return it->second;
stringList[13] = "HEADER_GC_STUN";
stringList[14] = "HEADER_GC_DEAD";
stringList[15] = "HEADER_GC_MAIN_CHARACTER";
stringList[16] = "HEADER_GC_PLAYER_POINTS";
stringList[17] = "HEADER_GC_PLAYER_POINT_CHANGE";
stringList[18] = "HEADER_GC_CHANGE_SPEED";
stringList[19] = "HEADER_GC_CHARACTER_UPDATE";
stringList[20] = "HEADER_GC_ITEM_DEL";
stringList[21] = "HEADER_GC_ITEM_SET";
stringList[22] = "HEADER_GC_ITEM_USE";
stringList[23] = "HEADER_GC_ITEM_DROP";
stringList[25] = "HEADER_GC_ITEM_UPDATE";
stringList[26] = "HEADER_GC_ITEM_GROUND_ADD";
stringList[27] = "HEADER_GC_ITEM_GROUND_DEL";
stringList[28] = "HEADER_GC_QUICKSLOT_ADD";
stringList[29] = "HEADER_GC_QUICKSLOT_DEL";
stringList[30] = "HEADER_GC_QUICKSLOT_SWAP";
stringList[31] = "HEADER_GC_ITEM_OWNERSHIP";
stringList[33] = "HEADER_GC_ITEM_UNBIND_TIME";
stringList[34] = "HEADER_GC_WHISPER";
stringList[35] = "HEADER_GC_ALERT";
stringList[36] = "HEADER_GC_MOTION";
stringList[38] = "HEADER_GC_SHOP";
stringList[39] = "HEADER_GC_SHOP_SIGN";
stringList[41] = "HEADER_GC_PVP";
stringList[42] = "HEADER_GC_EXCHANGE";
stringList[43] = "HEADER_GC_CHARACTER_POSITION";
stringList[44] = "HEADER_GC_PING";
stringList[45] = "HEADER_GC_SCRIPT";
stringList[46] = "HEADER_GC_QUEST_CONFIRM";
stringList[61] = "HEADER_GC_MOUNT";
stringList[62] = "HEADER_GC_OWNERSHIP";
stringList[63] = "HEADER_GC_TARGET";
stringList[65] = "HEADER_GC_WARP";
stringList[69] = "HEADER_GC_ADD_FLY_TARGETING";
stringList[70] = "HEADER_GC_CREATE_FLY";
stringList[71] = "HEADER_GC_FLY_TARGETING";
stringList[72] = "HEADER_GC_SKILL_LEVEL";
stringList[73] = "HEADER_GC_SKILL_COOLTIME_END";
stringList[74] = "HEADER_GC_MESSENGER";
stringList[75] = "HEADER_GC_GUILD";
stringList[76] = "HEADER_GC_SKILL_LEVEL_NEW";
stringList[77] = "HEADER_GC_PARTY_INVITE";
stringList[78] = "HEADER_GC_PARTY_ADD";
stringList[79] = "HEADER_GC_PARTY_UPDATE";
stringList[80] = "HEADER_GC_PARTY_REMOVE";
stringList[81] = "HEADER_GC_QUEST_INFO";
stringList[82] = "HEADER_GC_REQUEST_MAKE_GUILD";
stringList[83] = "HEADER_GC_PARTY_PARAMETER";
stringList[84] = "HEADER_GC_SAFEBOX_MONEY_CHANGE";
stringList[85] = "HEADER_GC_SAFEBOX_SET";
stringList[86] = "HEADER_GC_SAFEBOX_DEL";
stringList[87] = "HEADER_GC_SAFEBOX_WRONG_PASSWORD";
stringList[88] = "HEADER_GC_SAFEBOX_SIZE";
stringList[89] = "HEADER_GC_FISHING";
stringList[90] = "HEADER_GC_EMPIRE";
stringList[91] = "HEADER_GC_PARTY_LINK";
stringList[92] = "HEADER_GC_PARTY_UNLINK";
stringList[95] = "HEADER_GC_REFINE_INFORMATION";
stringList[96] = "HEADER_GC_OBSERVER_ADD";
stringList[97] = "HEADER_GC_OBSERVER_REMOVE";
stringList[98] = "HEADER_GC_OBSERVER_MOVE";
stringList[99] = "HEADER_GC_VIEW_EQUIP";
stringList[100] = "HEADER_GC_MARK_BLOCK";
stringList[101] = "HEADER_GC_MARK_DIFF_DATA";
stringList[106] = "HEADER_GC_TIME";
stringList[107] = "HEADER_GC_CHANGE_NAME";
stringList[110] = "HEADER_GC_DUNGEON";
stringList[111] = "HEADER_GC_WALK_MODE";
stringList[112] = "HEADER_GC_CHANGE_SKILL_GROUP";
stringList[113] = "HEADER_GC_MAIN_CHARACTER_NEW";
stringList[114] = "HEADER_GC_USE_POTION";
stringList[115] = "HEADER_GC_NPC_POSITION";
stringList[116] = "HEADER_GC_MATRIX_CARD";
stringList[117] = "HEADER_GC_CHARACTER_UPDATE2";
stringList[118] = "HEADER_GC_LOGIN_KEY";
stringList[119] = "HEADER_GC_REFINE_INFORMATION_NEW";
stringList[120] = "HEADER_GC_CHARACTER_ADD2";
stringList[121] = "HEADER_GC_CHANNEL";
stringList[122] = "HEADER_GC_MALL_OPEN";
stringList[123] = "HEADER_GC_TARGET_UPDATE";
stringList[124] = "HEADER_GC_TARGET_DELETE";
stringList[125] = "HEADER_GC_TARGET_CREATE_NEW";
stringList[126] = "HEADER_GC_AFFECT_ADD";
stringList[127] = "HEADER_GC_AFFECT_REMOVE";
stringList[128] = "HEADER_GC_MALL_SET";
stringList[129] = "HEADER_GC_MALL_DEL";
stringList[130] = "HEADER_GC_LAND_LIST";
stringList[131] = "HEADER_GC_LOVER_INFO";
stringList[132] = "HEADER_GC_LOVE_POINT_UPDATE";
stringList[133] = "HEADER_GC_GUILD_SYMBOL_DATA";
stringList[134] = "HEADER_GC_DIG_MOTION";
stringList[135] = "HEADER_GC_DAMAGE_INFO";
stringList[136] = "HEADER_GC_CHAR_ADDITIONAL_INFO";
stringList[150] = "HEADER_GC_AUTH_SUCCESS";
stringList[0xf7] = "HEADER_GC_KEY_COMPLETE";
stringList[0xf8] = "HEADER_GC_KEY_CHALLENGE";
stringList[0xfc] = "HEADER_GC_HANDSHAKE_OK";
stringList[0xfd] = "HEADER_GC_PHASE";
stringList[0xfe] = "HEADER_GC_BINDUDP";
stringList[0xff] = "HEADER_GC_HANDSHAKE";
}
return stringList[header].c_str();
static thread_local char buf[16];
snprintf(buf, sizeof(buf), "0x%04X", header);
return buf;
}
#endif
@@ -548,7 +484,7 @@ bool CNetworkStream::Recv(int size)
if (!Peek(size))
return false;
m_recvBufOutputPos += size;
m_recvBuf.Discard(static_cast<size_t>(size));
return true;
}
@@ -575,46 +511,61 @@ bool CNetworkStream::Recv(int size, char * pDestBuf)
return false;
#ifdef _PACKETDUMP
if (*pDestBuf != 0)
if (size >= 2)
{
const auto kHeader = *pDestBuf;
TraceError("RECV< %s %u(0x%X) (%d)", GetRecvHeaderName(kHeader), kHeader, kHeader, size);
const uint16_t kHeader = *reinterpret_cast<const uint16_t*>(pDestBuf);
TraceError("RECV< %s 0x%04X (%d bytes)", GetHeaderName(kHeader), kHeader, size);
const auto contents = dump_hex(reinterpret_cast<const uint8_t*>(pDestBuf), size);
TraceError("%s", contents.c_str());
}
#endif
m_recvBufOutputPos += size;
m_recvBuf.Discard(static_cast<size_t>(size));
return true;
}
int CNetworkStream::__GetSendBufferSize()
{
return m_sendBufInputPos - m_sendBufOutputPos;
return static_cast<int>(m_sendBuf.ReadableBytes());
}
bool CNetworkStream::Send(int size, const char * pSrcBuf)
{
int sendBufRestSize = m_sendBufSize - m_sendBufInputPos;
if ((size + 1) > sendBufRestSize)
return false;
memcpy(m_sendBuf + m_sendBufInputPos, pSrcBuf, size);
if (m_secureCipher.IsActivated())
// Track packet sends: detect new packet start by checking [header:2][length:2] framing
if (size >= 4)
{
m_secureCipher.EncryptInPlace(m_sendBuf + m_sendBufInputPos, size);
const uint16_t wHeader = *reinterpret_cast<const uint16_t*>(pSrcBuf);
const uint16_t wLength = *reinterpret_cast<const uint16_t*>(pSrcBuf + 2);
if (wHeader != 0 && wLength >= 4)
{
auto& e = m_aSentPacketLog[m_dwSentPacketSeq % SENT_PACKET_LOG_SIZE];
e.seq = m_dwSentPacketSeq;
e.header = wHeader;
e.length = wLength;
m_dwSentPacketSeq++;
}
}
m_sendBufInputPos += size;
m_sendBuf.EnsureWritable(static_cast<size_t>(size));
// Copy data to send buffer
std::memcpy(m_sendBuf.WritePtr(), pSrcBuf, static_cast<size_t>(size));
// Encrypt in-place before committing
if (m_secureCipher.IsActivated())
{
m_secureCipher.EncryptInPlace(m_sendBuf.WritePtr(), size);
}
m_sendBuf.CommitWrite(static_cast<size_t>(size));
#ifdef _PACKETDUMP
if (*pSrcBuf != 0)
if (size >= 2)
{
const auto kHeader = *pSrcBuf;
TraceError("SEND> %s %u(0x%X) (%d)", GetSendHeaderName(kHeader), kHeader, kHeader, size);
const uint16_t kHeader = *reinterpret_cast<const uint16_t*>(pSrcBuf);
TraceError("SEND> %s 0x%04X (%d bytes)", GetHeaderName(kHeader), kHeader, size);
const auto contents = dump_hex(reinterpret_cast<const uint8_t*>(pSrcBuf), size);
TraceError("%s", contents.c_str());
@@ -652,25 +603,6 @@ bool CNetworkStream::IsOnline()
return m_isOnline;
}
void CNetworkStream::SetPacketSequenceMode(bool isOn)
{
m_bUseSequence = isOn;
}
bool CNetworkStream::SendSequence()
{
if (!m_bUseSequence)
return true;
BYTE bSeq = m_SequenceGenerator(UINT8_MAX + 1);
return Send(sizeof(BYTE), &bSeq);
}
uint8_t CNetworkStream::GetNextSequence()
{
return m_SequenceGenerator(UINT8_MAX + 1);
}
bool CNetworkStream::OnProcess()
{
return true;
@@ -694,6 +626,96 @@ void CNetworkStream::OnConnectFailure()
Tracen("Failed to connect.");
}
// ---------------------------------------------------------------------------
// Control-plane packet handlers (shared by all connection types)
// ---------------------------------------------------------------------------
bool CNetworkStream::RecvKeyChallenge()
{
TPacketGCKeyChallenge packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracen("KEY_CHALLENGE RECV");
SecureCipher& cipher = GetSecureCipher();
if (!cipher.Initialize())
{
TraceError("SecureCipher initialization failed");
Disconnect();
return false;
}
if (!cipher.ComputeClientKeys(packet.server_pk))
{
TraceError("Failed to compute client session keys");
Disconnect();
return false;
}
TPacketCGKeyResponse response;
response.header = CG::KEY_RESPONSE;
response.length = sizeof(response);
cipher.GetPublicKey(response.client_pk);
cipher.ComputeChallengeResponse(packet.challenge, response.challenge_response);
if (!Send(sizeof(response), &response))
{
TraceError("Failed to send key response");
return false;
}
Tracen("KEY_RESPONSE SENT");
return true;
}
bool CNetworkStream::RecvKeyComplete()
{
TPacketGCKeyComplete packet;
if (!Recv(sizeof(packet), &packet))
return false;
SecureCipher& cipher = GetSecureCipher();
uint8_t decrypted_token[SecureCipher::SESSION_TOKEN_SIZE];
if (!cipher.DecryptToken(packet.encrypted_token, sizeof(packet.encrypted_token),
packet.nonce, decrypted_token))
{
TraceError("Failed to decrypt session token");
Disconnect();
return false;
}
cipher.SetSessionToken(decrypted_token);
cipher.SetActivated(true);
DecryptPendingRecvData();
return true;
}
bool CNetworkStream::RecvPingPacket()
{
TPacketGCPing kPacketPing;
if (!Recv(sizeof(kPacketPing), &kPacketPing))
return false;
return SendPongPacket();
}
bool CNetworkStream::SendPongPacket()
{
TPacketCGPong kPacketPong;
kPacketPong.header = CG::PONG;
kPacketPong.length = sizeof(kPacketPong);
if (!Send(sizeof(kPacketPong), &kPacketPong))
return false;
return true;
}
// ---------------------------------------------------------------------------
CNetworkStream::CNetworkStream()
{
m_sock = INVALID_SOCKET;
@@ -701,33 +723,9 @@ CNetworkStream::CNetworkStream()
m_isOnline = false;
m_connectLimitTime = 0;
m_recvBuf = NULL;
m_recvBufSize = 0;
m_recvBufOutputPos = 0;
m_recvBufInputPos = 0;
m_sendBuf = NULL;
m_sendBufSize = 0;
m_sendBufOutputPos = 0;
m_sendBufInputPos = 0;
m_SequenceGenerator.seed(SEQUENCE_SEED);
m_bUseSequence = false;
}
CNetworkStream::~CNetworkStream()
{
Clear();
if (m_recvBuf)
{
delete [] m_recvBuf;
m_recvBuf = NULL;
}
if (m_sendBuf)
{
delete [] m_sendBuf;
m_sendBuf = NULL;
}
}

View File

@@ -2,10 +2,9 @@
#include "EterBase/SecureCipher.h"
#include "NetAddress.h"
#include "RingBuffer.h"
#include "ControlPackets.h"
#include <pcg_random.hpp>
#define SEQUENCE_SEED 0
class CNetworkStream
{
@@ -44,10 +43,6 @@ class CNetworkStream
bool IsOnline();
void SetPacketSequenceMode(bool isOn);
bool SendSequence();
uint8_t GetNextSequence();
protected:
virtual void OnConnectSuccess();
virtual void OnConnectFailure();
@@ -58,8 +53,6 @@ class CNetworkStream
bool __SendInternalBuffer();
bool __RecvInternalBuffer();
void __PopSendBuffer();
int __GetSendBufferSize();
// Secure cipher methods (libsodium)
@@ -71,18 +64,31 @@ class CNetworkStream
// Must be called after activating the cipher mid-stream
void DecryptPendingRecvData();
// Control-plane packet handlers (shared by all connection types)
virtual bool RecvKeyChallenge();
virtual bool RecvKeyComplete();
bool RecvPingPacket();
bool SendPongPacket();
// Packet send tracking (for debug sequence correlation)
protected:
struct SentPacketLogEntry
{
uint32_t seq;
uint16_t header;
uint16_t length;
};
static constexpr size_t SENT_PACKET_LOG_SIZE = 32;
SentPacketLogEntry m_aSentPacketLog[SENT_PACKET_LOG_SIZE] = {};
uint32_t m_dwSentPacketSeq = 0;
private:
time_t m_connectLimitTime;
char* m_recvBuf;
int m_recvBufSize;
int m_recvBufInputPos;
int m_recvBufOutputPos;
char* m_sendBuf;
int m_sendBufSize;
int m_sendBufInputPos;
int m_sendBufOutputPos;
RingBuffer m_recvBuf;
RingBuffer m_sendBuf;
bool m_isOnline;
@@ -93,7 +99,4 @@ class CNetworkStream
CNetworkAddress m_addr;
// Sequence
pcg32 m_SequenceGenerator;
bool m_bUseSequence;
};

157
src/EterLib/PacketReader.h Normal file
View File

@@ -0,0 +1,157 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <cassert>
// PacketReader: Safe, bounds-checked packet deserialization from a read-only buffer.
// Used to parse incoming packets after the dispatch loop validates the header and length.
//
// Usage:
// PacketReader r(packetData, packetLength);
// uint16_t header = r.ReadU16();
// uint16_t length = r.ReadU16();
// uint8_t chatType = r.ReadU8();
// char message[128];
// r.ReadString(message, sizeof(message));
class PacketReader
{
public:
PacketReader(const void* data, size_t size)
: m_buf(static_cast<const uint8_t*>(data))
, m_size(size)
, m_pos(0)
{
assert(data != nullptr || size == 0);
}
// --- Read primitives ---
uint8_t ReadU8()
{
assert(m_pos + sizeof(uint8_t) <= m_size);
return m_buf[m_pos++];
}
uint16_t ReadU16()
{
assert(m_pos + sizeof(uint16_t) <= m_size);
uint16_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
uint32_t ReadU32()
{
assert(m_pos + sizeof(uint32_t) <= m_size);
uint32_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
int8_t ReadI8() { return static_cast<int8_t>(ReadU8()); }
int16_t ReadI16() { return static_cast<int16_t>(ReadU16()); }
int32_t ReadI32() { return static_cast<int32_t>(ReadU32()); }
uint64_t ReadU64()
{
assert(m_pos + sizeof(uint64_t) <= m_size);
uint64_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
float ReadFloat()
{
assert(m_pos + sizeof(float) <= m_size);
float v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
// Read raw bytes
bool ReadBytes(void* dest, size_t len)
{
if (m_pos + len > m_size)
return false;
std::memcpy(dest, m_buf + m_pos, len);
m_pos += len;
return true;
}
// Read a fixed-length string (null-terminated in dest)
bool ReadString(char* dest, size_t fixedLen)
{
if (m_pos + fixedLen > m_size)
return false;
std::memcpy(dest, m_buf + m_pos, fixedLen);
dest[fixedLen - 1] = '\0'; // ensure null termination
m_pos += fixedLen;
return true;
}
// Skip bytes without reading
bool Skip(size_t len)
{
if (m_pos + len > m_size)
return false;
m_pos += len;
return true;
}
// --- Peek (non-consuming) ---
uint8_t PeekU8() const
{
assert(m_pos + sizeof(uint8_t) <= m_size);
return m_buf[m_pos];
}
uint16_t PeekU16() const
{
assert(m_pos + sizeof(uint16_t) <= m_size);
uint16_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
return v;
}
uint16_t PeekU16At(size_t offset) const
{
assert(offset + sizeof(uint16_t) <= m_size);
uint16_t v;
std::memcpy(&v, m_buf + offset, sizeof(v));
return v;
}
// --- Read struct (for backward compatibility during migration) ---
// Reads a struct directly via memcpy. Use sparingly — prefer typed reads.
template<typename T>
bool ReadStruct(T& out)
{
if (m_pos + sizeof(T) > m_size)
return false;
std::memcpy(&out, m_buf + m_pos, sizeof(T));
m_pos += sizeof(T);
return true;
}
// --- State ---
bool HasBytes(size_t n) const { return (m_pos + n) <= m_size; }
size_t Remaining() const { return m_size - m_pos; }
size_t Position() const { return m_pos; }
size_t Size() const { return m_size; }
const uint8_t* Current() const { return m_buf + m_pos; }
void Reset() { m_pos = 0; }
private:
const uint8_t* m_buf;
size_t m_size;
size_t m_pos;
};

139
src/EterLib/PacketWriter.h Normal file
View File

@@ -0,0 +1,139 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <cassert>
// PacketWriter: Safe, bounds-checked packet serialization into a fixed buffer.
// Used to build outgoing packets before writing to the send buffer.
//
// Usage:
// uint8_t buf[128];
// PacketWriter w(buf, sizeof(buf));
// w.WriteU16(CG::CHAT);
// w.WriteU16(0); // placeholder for length
// w.WriteU8(chatType);
// w.WriteString(message, 128);
// w.PatchU16(2, w.Written()); // patch length at offset 2
// stream.Send(w.Written(), buf);
class PacketWriter
{
public:
PacketWriter(void* buf, size_t capacity)
: m_buf(static_cast<uint8_t*>(buf))
, m_capacity(capacity)
, m_pos(0)
{
assert(buf != nullptr);
assert(capacity > 0);
}
// --- Write primitives ---
bool WriteU8(uint8_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
m_buf[m_pos++] = v;
return true;
}
bool WriteU16(uint16_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
bool WriteU32(uint32_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
bool WriteI8(int8_t v) { return WriteU8(static_cast<uint8_t>(v)); }
bool WriteI16(int16_t v) { return WriteU16(static_cast<uint16_t>(v)); }
bool WriteI32(int32_t v) { return WriteU32(static_cast<uint32_t>(v)); }
bool WriteU64(uint64_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
bool WriteFloat(float v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
// Write raw bytes
bool WriteBytes(const void* data, size_t len)
{
if (len == 0)
return true;
if (m_pos + len > m_capacity)
return false;
std::memcpy(m_buf + m_pos, data, len);
m_pos += len;
return true;
}
// Write a fixed-length null-padded string
bool WriteString(const char* str, size_t fixedLen)
{
if (m_pos + fixedLen > m_capacity)
return false;
size_t srcLen = str ? std::strlen(str) : 0;
size_t copyLen = (srcLen < fixedLen) ? srcLen : (fixedLen - 1);
std::memcpy(m_buf + m_pos, str, copyLen);
std::memset(m_buf + m_pos + copyLen, 0, fixedLen - copyLen);
m_pos += fixedLen;
return true;
}
// --- Patch: overwrite data at a previous offset ---
bool PatchU16(size_t offset, uint16_t v)
{
if (offset + sizeof(v) > m_pos)
return false;
std::memcpy(m_buf + offset, &v, sizeof(v));
return true;
}
bool PatchU32(size_t offset, uint32_t v)
{
if (offset + sizeof(v) > m_pos)
return false;
std::memcpy(m_buf + offset, &v, sizeof(v));
return true;
}
// --- State ---
size_t Written() const { return m_pos; }
size_t Remaining() const { return m_capacity - m_pos; }
const uint8_t* Data() const { return m_buf; }
void Reset() { m_pos = 0; }
private:
uint8_t* m_buf;
size_t m_capacity;
size_t m_pos;
};

View File

@@ -1,264 +1 @@
#pragma once
#include "EterBase/Timer.h"
#include "EterBase/Debug.h"
/*
class CProfiler : public CSingleton<CProfiler>
{
public:
enum
{
STACK_DATA_MAX_NUM = 64,
};
public:
typedef struct SProfileStackData
{
int iCallStep;
long iStartTime;
long iEndTime;
std::string strName;
} TProfileStackData;
typedef struct SProfileAccumulationData
{
int iStartTime;
int iCallingCount;
int iCollapsedTime;
std::string strName;
} TProfileAccumulationData;
typedef std::map<std::string, CGraphicTextInstance*> TGraphicTextInstanceMap;
typedef std::map<std::string, TProfileAccumulationData> TProfileAccumulationDataMap;
public:
CProfiler()
{
Clear();
m_ProfileAccumulationDataMap.clear();
}
virtual ~CProfiler()
{
}
void Clear()
{
m_ProfileStackDataCount = 0;
m_iCallStep = 0;
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.begin();
for (; itor != m_ProfileAccumulationDataMap.end(); ++itor)
{
TProfileAccumulationData & rData = itor->second;
rData.iCallingCount = 0;
rData.iCollapsedTime = 0;
}
}
void Push(const char * c_szName)
{
assert(m_ProfileStackDataCount < STACK_DATA_MAX_NUM);
TProfileStackData & rProfileStackData = m_ProfileStackDatas[m_ProfileStackDataCount++];
rProfileStackData.iCallStep = m_iCallStep;
rProfileStackData.iStartTime = ELTimer_GetMSec();
rProfileStackData.strName = c_szName;
++m_iCallStep;
TGraphicTextInstanceMap::iterator itor = m_GraphicTextInstanceMap.find(c_szName);
if (m_GraphicTextInstanceMap.end() == itor)
{
CGraphicTextInstance * pGraphicTextInstance = CGraphicTextInstance::New();
CResource * pResource = CResourceManager::Instance().GetResourcePointer("굴림체.fnt");
pGraphicTextInstance->Clear();
pGraphicTextInstance->SetTextPointer(static_cast<CGraphicText*>(pResource));
m_GraphicTextInstanceMap.insert(TGraphicTextInstanceMap::value_type(c_szName, pGraphicTextInstance));
}
}
void Pop(const char * c_szName)
{
TProfileStackData * pProfileStackData;
if (!GetProfileStackDataPointer(c_szName, &pProfileStackData))
{
assert(!"The name doesn't exist");
return;
}
pProfileStackData->iEndTime = ELTimer_GetMSec();
--m_iCallStep;
}
void PushAccumulation(const char * c_szName)
{
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.find(c_szName);
if (itor == m_ProfileAccumulationDataMap.end())
{
TProfileAccumulationData ProfileAccumulationData;
ProfileAccumulationData.iCollapsedTime = 0;
ProfileAccumulationData.iCallingCount = 0;
ProfileAccumulationData.strName = c_szName;
m_ProfileAccumulationDataMap.insert(TProfileAccumulationDataMap::value_type(c_szName, ProfileAccumulationData));
itor = m_ProfileAccumulationDataMap.find(c_szName);
/////
CGraphicTextInstance * pGraphicTextInstance = m_GraphicTextInstancePool.Alloc();
CResource * pResource = CResourceManager::Instance().GetResourcePointer("굴림체.fnt");
pGraphicTextInstance->Clear();
pGraphicTextInstance->SetTextPointer(static_cast<CGraphicText*>(pResource));
m_GraphicTextInstanceMap.insert(TGraphicTextInstanceMap::value_type(c_szName, pGraphicTextInstance));
}
TProfileAccumulationData & rData = itor->second;
rData.iStartTime = ELTimer_GetMSec();
}
void PopAccumulation(const char * c_szName)
{
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.find(c_szName);
if (itor == m_ProfileAccumulationDataMap.end())
return;
TProfileAccumulationData & rData = itor->second;
rData.iCollapsedTime += ELTimer_GetMSec() - rData.iStartTime;
++rData.iCallingCount;
}
void ProfileByConsole()
{
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
TProfileStackData & rProfileStackData = m_ProfileStackDatas[i];
// for (int i = 0; i < rProfileStackData.iCallStep; ++i)
// Tracef("\t");
Tracef("%-10s: %2d\t", rProfileStackData.strName.c_str(), rProfileStackData.iEndTime - rProfileStackData.iStartTime);
}
Tracef("\n");
}
void ProfileOneStackDataByConsole(const char * c_szName)
{
TProfileStackData * pProfileStackData;
if (!GetProfileStackDataPointer(c_szName, &pProfileStackData))
{
return;
}
Tracef("%-10s: %3d\n", pProfileStackData->strName.c_str(), pProfileStackData->iEndTime - pProfileStackData->iStartTime);
}
void ProfileOneAccumulationDataByConsole(const char * c_szName)
{
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.find(c_szName);
if (itor == m_ProfileAccumulationDataMap.end())
return;
TProfileAccumulationData & rData = itor->second;
Tracef("%-10s : [CollapsedTime : %3d] / [CallingCount : %3d]\n", rData.strName.c_str(),
rData.iCollapsedTime,
rData.iCallingCount);
}
void ProfileByScreen()
{
float fxPosition = 0;
float fyPosition = 10;
char szText[128];
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
TProfileStackData & rProfileStackData = m_ProfileStackDatas[i];
TGraphicTextInstanceMap::iterator itor = m_GraphicTextInstanceMap.find(rProfileStackData.strName);
if (m_GraphicTextInstanceMap.end() != itor)
{
CGraphicTextInstance * pGraphicTextInstance = itor->second;
fxPosition = 10 + (float) rProfileStackData.iCallStep * 10 * 4;
sprintf(szText, "%-10s : %3d", rProfileStackData.strName.c_str(), rProfileStackData.iEndTime - rProfileStackData.iStartTime);
pGraphicTextInstance->SetColor(0.7f, 0.7f, 0.7f);
pGraphicTextInstance->SetValue(szText, strlen(szText));
pGraphicTextInstance->SetPosition(fxPosition, fyPosition);
pGraphicTextInstance->Update();
pGraphicTextInstance->Render();
fyPosition += 17;
}
}
fxPosition = 10;
fyPosition += 10;
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.begin();
for (; itor != m_ProfileAccumulationDataMap.end(); ++itor)
{
TProfileAccumulationData & rData = itor->second;
TGraphicTextInstanceMap::iterator itor = m_GraphicTextInstanceMap.find(rData.strName);
if (m_GraphicTextInstanceMap.end() != itor)
{
CGraphicTextInstance * pGraphicTextInstance = itor->second;
sprintf(szText, "%-10s : [CollapsedTime : %3d] / [CallingCount : %3d]", rData.strName.c_str(),
rData.iCollapsedTime,
rData.iCallingCount);
pGraphicTextInstance->SetColor(0.7f, 0.7f, 0.7f);
pGraphicTextInstance->SetValue(szText, strlen(szText));
pGraphicTextInstance->SetPosition(fxPosition, fyPosition);
pGraphicTextInstance->Update();
pGraphicTextInstance->Render();
fyPosition += 17;
}
}
}
protected:
bool GetProfileStackDataPointer(const char * c_szName, TProfileStackData ** ppProfileStackData)
{
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
if (0 == m_ProfileStackDatas[i].strName.compare(c_szName))
{
*ppProfileStackData = &m_ProfileStackDatas[i];
return true;
}
}
return false;
}
protected:
// Profile Stack Data
int m_ProfileStackDataCount;
TProfileStackData m_ProfileStackDatas[STACK_DATA_MAX_NUM];
// Profile Increase Data
TProfileAccumulationDataMap m_ProfileAccumulationDataMap;
int m_iCallStep;
TGraphicTextInstanceMap m_GraphicTextInstanceMap;
};
*/

191
src/EterLib/RingBuffer.h Normal file
View File

@@ -0,0 +1,191 @@
#pragma once
#include <vector>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <algorithm>
class RingBuffer
{
public:
explicit RingBuffer(size_t initialCapacity = 0)
{
if (initialCapacity > 0)
m_data.resize(initialCapacity);
}
~RingBuffer() = default;
// Non-copyable, movable
RingBuffer(const RingBuffer&) = delete;
RingBuffer& operator=(const RingBuffer&) = delete;
RingBuffer(RingBuffer&&) noexcept = default;
RingBuffer& operator=(RingBuffer&&) noexcept = default;
// --- Capacity ---
size_t ReadableBytes() const { return m_writePos - m_readPos; }
size_t WritableBytes() const { return m_data.size() - m_writePos; }
size_t Capacity() const { return m_data.size(); }
void Reserve(size_t capacity)
{
if (capacity > m_data.size())
{
Compact();
m_data.resize(capacity);
}
}
void EnsureWritable(size_t len)
{
if (WritableBytes() >= len)
return;
// Try compaction first
Compact();
if (WritableBytes() >= len)
return;
// Must grow
size_t needed = m_writePos + len;
size_t newSize = m_data.size();
if (newSize == 0)
newSize = 1024;
while (newSize < needed)
newSize *= 2;
m_data.resize(newSize);
}
// --- Write operations ---
void Write(const void* data, size_t len)
{
if (len == 0)
return;
assert(data != nullptr);
EnsureWritable(len);
std::memcpy(m_data.data() + m_writePos, data, len);
m_writePos += len;
}
// Direct write access for socket recv()
uint8_t* WritePtr()
{
return m_data.data() + m_writePos;
}
void CommitWrite(size_t len)
{
assert(m_writePos + len <= m_data.size());
m_writePos += len;
}
// --- Read operations ---
bool HasBytes(size_t n) const { return ReadableBytes() >= n; }
bool Peek(void* dest, size_t len) const
{
if (ReadableBytes() < len)
return false;
std::memcpy(dest, m_data.data() + m_readPos, len);
return true;
}
// Peek at a specific offset from read position (non-consuming)
bool PeekAt(size_t offset, void* dest, size_t len) const
{
if (ReadableBytes() < offset + len)
return false;
std::memcpy(dest, m_data.data() + m_readPos + offset, len);
return true;
}
bool Read(void* dest, size_t len)
{
if (!Peek(dest, len))
return false;
m_readPos += len;
MaybeCompact();
return true;
}
// Discard bytes without reading them
bool Discard(size_t len)
{
if (ReadableBytes() < len)
return false;
m_readPos += len;
MaybeCompact();
return true;
}
// Direct read access for socket send() and packet processing
const uint8_t* ReadPtr() const
{
return m_data.data() + m_readPos;
}
size_t ReadPos() const { return m_readPos; }
size_t WritePos() const { return m_writePos; }
// --- Encryption support ---
// Get writable pointer to already-written data at a specific position
// Used for in-place encryption of data that was just written
uint8_t* DataAt(size_t pos)
{
assert(pos < m_data.size());
return m_data.data() + pos;
}
// --- Reset ---
void Clear()
{
m_readPos = 0;
m_writePos = 0;
}
// --- Compaction ---
void Compact()
{
if (m_readPos == 0)
return;
size_t readable = ReadableBytes();
if (readable > 0)
std::memmove(m_data.data(), m_data.data() + m_readPos, readable);
m_readPos = 0;
m_writePos = readable;
}
private:
void MaybeCompact()
{
// Compact when read position passes halfway and there's no readable data
// or when read position is more than half the buffer
if (m_readPos == m_writePos)
{
m_readPos = 0;
m_writePos = 0;
}
else if (m_readPos > m_data.size() / 2)
{
Compact();
}
}
std::vector<uint8_t> m_data;
size_t m_readPos = 0;
size_t m_writePos = 0;
};