mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-13 11:38:19 +00:00
1d81d56850
This means that we have a reliable and fast way to query for extended info, while also not wasting network bandwidth. The protocol is designed to be extensible, there's four bytes space for encoding more request types (currently zeroed), and there's one string in each response packet and one string for each player available (currently the empty string). The protocol itself has no problems with more than 64 players, although the current client implementation will drop the player info after the 64th player, because it uses a static array for storage. Also fixes #130, the player list is just sorted each time new player info arrives.
165 lines
2.5 KiB
C++
165 lines
2.5 KiB
C++
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
|
#include <base/system.h>
|
|
|
|
#include "packer.h"
|
|
#include "compression.h"
|
|
#include "config.h"
|
|
|
|
void CPacker::Reset()
|
|
{
|
|
m_Error = 0;
|
|
m_pCurrent = m_aBuffer;
|
|
m_pEnd = m_pCurrent + PACKER_BUFFER_SIZE;
|
|
}
|
|
|
|
void CPacker::AddInt(int i)
|
|
{
|
|
if(m_Error)
|
|
return;
|
|
|
|
// make sure that we have space enough
|
|
if(m_pEnd - m_pCurrent < 6)
|
|
{
|
|
dbg_break();
|
|
m_Error = 1;
|
|
}
|
|
else
|
|
m_pCurrent = CVariableInt::Pack(m_pCurrent, i);
|
|
}
|
|
|
|
void CPacker::AddString(const char *pStr, int Limit)
|
|
{
|
|
if(m_Error)
|
|
return;
|
|
|
|
//
|
|
if(Limit > 0)
|
|
{
|
|
while(*pStr && Limit != 0)
|
|
{
|
|
*m_pCurrent++ = *pStr++;
|
|
Limit--;
|
|
|
|
if(m_pCurrent >= m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
break;
|
|
}
|
|
}
|
|
*m_pCurrent++ = 0;
|
|
}
|
|
else
|
|
{
|
|
while(*pStr)
|
|
{
|
|
*m_pCurrent++ = *pStr++;
|
|
|
|
if(m_pCurrent >= m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
break;
|
|
}
|
|
}
|
|
*m_pCurrent++ = 0;
|
|
}
|
|
}
|
|
|
|
void CPacker::AddRaw(const void *pData, int Size)
|
|
{
|
|
if(m_Error)
|
|
return;
|
|
|
|
if(m_pCurrent+Size >= m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
return;
|
|
}
|
|
|
|
const unsigned char *pSrc = (const unsigned char *)pData;
|
|
while(Size)
|
|
{
|
|
*m_pCurrent++ = *pSrc++;
|
|
Size--;
|
|
}
|
|
}
|
|
|
|
|
|
void CUnpacker::Reset(const void *pData, int Size)
|
|
{
|
|
m_Error = 0;
|
|
m_pStart = (const unsigned char *)pData;
|
|
m_pEnd = m_pStart + Size;
|
|
m_pCurrent = m_pStart;
|
|
}
|
|
|
|
int CUnpacker::GetInt()
|
|
{
|
|
if(m_Error)
|
|
return 0;
|
|
|
|
if(m_pCurrent >= m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
return 0;
|
|
}
|
|
|
|
int i;
|
|
m_pCurrent = CVariableInt::Unpack(m_pCurrent, &i);
|
|
if(m_pCurrent > m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
return 0;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
const char *CUnpacker::GetString(int SanitizeType)
|
|
{
|
|
if(m_Error)
|
|
return "";
|
|
|
|
if(m_pCurrent >= m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
return "";
|
|
}
|
|
|
|
char *pPtr = (char *)m_pCurrent;
|
|
while(*m_pCurrent) // skip the string
|
|
{
|
|
m_pCurrent++;
|
|
if(m_pCurrent == m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
return "";
|
|
}
|
|
}
|
|
m_pCurrent++;
|
|
|
|
// sanitize all strings
|
|
if(SanitizeType&SANITIZE)
|
|
str_sanitize(pPtr);
|
|
else if(SanitizeType&SANITIZE_CC)
|
|
str_sanitize_cc(pPtr);
|
|
return SanitizeType&SKIP_START_WHITESPACES ? str_utf8_skip_whitespaces(pPtr) : pPtr;
|
|
}
|
|
|
|
const unsigned char *CUnpacker::GetRaw(int Size)
|
|
{
|
|
const unsigned char *pPtr = m_pCurrent;
|
|
if(m_Error)
|
|
return 0;
|
|
|
|
// check for nasty sizes
|
|
if(Size < 0 || m_pCurrent+Size > m_pEnd)
|
|
{
|
|
m_Error = 1;
|
|
return 0;
|
|
}
|
|
|
|
// "unpack" the data
|
|
m_pCurrent += Size;
|
|
return pPtr;
|
|
}
|