mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-11 02:28:18 +00:00
190 lines
5.7 KiB
C++
190 lines
5.7 KiB
C++
|
#include "serverinfo.h"
|
||
|
|
||
|
#include "json.h"
|
||
|
#include <engine/external/json-parser/json.h>
|
||
|
#include <engine/serverbrowser.h>
|
||
|
|
||
|
static bool IsAllowedHex(char c)
|
||
|
{
|
||
|
static const char ALLOWED[] = "0123456789abcdefABCDEF";
|
||
|
for(int i = 0; i < (int)sizeof(ALLOWED) - 1; i++)
|
||
|
{
|
||
|
if(c == ALLOWED[i])
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool ParseCrc(unsigned int *pResult, const char *pString)
|
||
|
{
|
||
|
if(str_length(pString) != 8)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
for(int i = 0; i < 8; i++)
|
||
|
{
|
||
|
if(!IsAllowedHex(pString[i]))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return sscanf(pString, "%08x", pResult) != 1;
|
||
|
}
|
||
|
|
||
|
bool CServerInfo2::FromJson(CServerInfo2 *pOut, const json_value *pJson)
|
||
|
{
|
||
|
bool Result = FromJsonRaw(pOut, pJson);
|
||
|
if(Result)
|
||
|
{
|
||
|
return Result;
|
||
|
}
|
||
|
return pOut->Validate();
|
||
|
}
|
||
|
|
||
|
bool CServerInfo2::Validate() const
|
||
|
{
|
||
|
bool Error = false;
|
||
|
Error = Error || m_MaxClients < m_MaxPlayers;
|
||
|
Error = Error || m_NumClients < m_NumPlayers;
|
||
|
Error = Error || m_MaxClients < m_NumClients;
|
||
|
Error = Error || m_MaxPlayers < m_NumPlayers;
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
bool CServerInfo2::FromJsonRaw(CServerInfo2 *pOut, const json_value *pJson)
|
||
|
{
|
||
|
mem_zero(pOut, sizeof(*pOut));
|
||
|
bool Error;
|
||
|
|
||
|
const json_value &ServerInfo = *pJson;
|
||
|
const json_value &MaxClients = ServerInfo["max_clients"];
|
||
|
const json_value &MaxPlayers = ServerInfo["max_players"];
|
||
|
const json_value &Passworded = ServerInfo["passworded"];
|
||
|
const json_value &GameType = ServerInfo["game_type"];
|
||
|
const json_value &Name = ServerInfo["name"];
|
||
|
const json_value &MapName = ServerInfo["map"]["name"];
|
||
|
const json_value &Version = ServerInfo["version"];
|
||
|
const json_value &Clients = ServerInfo["clients"];
|
||
|
Error = false;
|
||
|
Error = Error || MaxClients.type != json_integer;
|
||
|
Error = Error || MaxPlayers.type != json_integer;
|
||
|
Error = Error || Passworded.type != json_boolean;
|
||
|
Error = Error || GameType.type != json_string;
|
||
|
Error = Error || Name.type != json_string;
|
||
|
Error = Error || MapName.type != json_string;
|
||
|
Error = Error || Version.type != json_string;
|
||
|
Error = Error || Clients.type != json_array;
|
||
|
if(Error)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
pOut->m_MaxClients = MaxClients;
|
||
|
pOut->m_MaxPlayers = MaxPlayers;
|
||
|
pOut->m_Passworded = Passworded;
|
||
|
str_copy(pOut->m_aGameType, GameType, sizeof(pOut->m_aGameType));
|
||
|
str_copy(pOut->m_aName, Name, sizeof(pOut->m_aName));
|
||
|
str_copy(pOut->m_aMapName, MapName, sizeof(pOut->m_aMapName));
|
||
|
str_copy(pOut->m_aVersion, Version, sizeof(pOut->m_aVersion));
|
||
|
|
||
|
pOut->m_NumClients = 0;
|
||
|
pOut->m_NumPlayers = 0;
|
||
|
for(unsigned i = 0; i < Clients.u.array.length; i++)
|
||
|
{
|
||
|
const json_value &Client = Clients[i];
|
||
|
const json_value &Name = Client["name"];
|
||
|
const json_value &Clan = Client["clan"];
|
||
|
const json_value &Country = Client["country"];
|
||
|
const json_value &Score = Client["score"];
|
||
|
const json_value &IsPlayer = Client["is_player"];
|
||
|
Error = false;
|
||
|
Error = Error || Name.type != json_string;
|
||
|
Error = Error || Clan.type != json_string;
|
||
|
Error = Error || Country.type != json_integer;
|
||
|
Error = Error || Score.type != json_integer;
|
||
|
Error = Error || IsPlayer.type != json_boolean;
|
||
|
if(Error)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
if(i < MAX_CLIENTS)
|
||
|
{
|
||
|
CClient *pClient = &pOut->m_aClients[i];
|
||
|
str_copy(pClient->m_aName, Name, sizeof(pClient->m_aName));
|
||
|
str_copy(pClient->m_aClan, Clan, sizeof(pClient->m_aClan));
|
||
|
pClient->m_Country = Country;
|
||
|
pClient->m_Score = Score;
|
||
|
pClient->m_IsPlayer = IsPlayer;
|
||
|
}
|
||
|
|
||
|
pOut->m_NumClients++;
|
||
|
if((bool)IsPlayer)
|
||
|
{
|
||
|
pOut->m_NumPlayers++;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CServerInfo2::operator==(const CServerInfo2 &Other) const
|
||
|
{
|
||
|
bool Unequal;
|
||
|
Unequal = false;
|
||
|
Unequal = Unequal || m_MaxClients != Other.m_MaxClients;
|
||
|
Unequal = Unequal || m_NumClients != Other.m_NumClients;
|
||
|
Unequal = Unequal || m_MaxPlayers != Other.m_MaxPlayers;
|
||
|
Unequal = Unequal || m_NumPlayers != Other.m_NumPlayers;
|
||
|
Unequal = Unequal || m_Passworded != Other.m_Passworded;
|
||
|
Unequal = Unequal || str_comp(m_aGameType, Other.m_aGameType) != 0;
|
||
|
Unequal = Unequal || str_comp(m_aName, Other.m_aName) != 0;
|
||
|
Unequal = Unequal || str_comp(m_aMapName, Other.m_aMapName) != 0;
|
||
|
Unequal = Unequal || str_comp(m_aVersion, Other.m_aVersion) != 0;
|
||
|
if(Unequal)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
for(int i = 0; i < m_NumClients; i++)
|
||
|
{
|
||
|
Unequal = false;
|
||
|
Unequal = Unequal || str_comp(m_aClients[i].m_aName, Other.m_aClients[i].m_aName) != 0;
|
||
|
Unequal = Unequal || str_comp(m_aClients[i].m_aClan, Other.m_aClients[i].m_aClan) != 0;
|
||
|
Unequal = Unequal || m_aClients[i].m_Country != Other.m_aClients[i].m_Country;
|
||
|
Unequal = Unequal || m_aClients[i].m_Score != Other.m_aClients[i].m_Score;
|
||
|
Unequal = Unequal || m_aClients[i].m_IsPlayer != Other.m_aClients[i].m_IsPlayer;
|
||
|
if(Unequal)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
CServerInfo2::operator CServerInfo() const
|
||
|
{
|
||
|
CServerInfo Result = {0};
|
||
|
Result.m_MaxClients = m_MaxClients;
|
||
|
Result.m_NumClients = m_NumClients;
|
||
|
Result.m_MaxPlayers = m_MaxPlayers;
|
||
|
Result.m_NumPlayers = m_NumPlayers;
|
||
|
Result.m_Flags = m_Passworded ? SERVER_FLAG_PASSWORD : 0;
|
||
|
str_copy(Result.m_aGameType, m_aGameType, sizeof(Result.m_aGameType));
|
||
|
str_copy(Result.m_aName, m_aName, sizeof(Result.m_aName));
|
||
|
str_copy(Result.m_aMap, m_aMapName, sizeof(Result.m_aMap));
|
||
|
str_copy(Result.m_aVersion, m_aVersion, sizeof(Result.m_aVersion));
|
||
|
|
||
|
for(int i = 0; i < std::min(m_NumClients, (int)MAX_CLIENTS); i++)
|
||
|
{
|
||
|
str_copy(Result.m_aClients[i].m_aName, m_aClients[i].m_aName, sizeof(Result.m_aClients[i].m_aName));
|
||
|
str_copy(Result.m_aClients[i].m_aClan, m_aClients[i].m_aClan, sizeof(Result.m_aClients[i].m_aClan));
|
||
|
Result.m_aClients[i].m_Country = m_aClients[i].m_Country;
|
||
|
Result.m_aClients[i].m_Score = m_aClients[i].m_Score;
|
||
|
Result.m_aClients[i].m_Player = m_aClients[i].m_IsPlayer;
|
||
|
}
|
||
|
|
||
|
Result.m_NumReceivedClients = std::min(m_NumClients, (int)MAX_CLIENTS);
|
||
|
Result.m_Latency = -1;
|
||
|
|
||
|
return Result;
|
||
|
}
|