Use CJsonWriter for creating server info JSON

This commit is contained in:
furo 2024-08-23 20:07:11 +02:00
parent 37fd57ccb8
commit f897af8dbb
4 changed files with 94 additions and 105 deletions

View file

@ -12,6 +12,7 @@
#include "kernel.h" #include "kernel.h"
#include "message.h" #include "message.h"
#include <engine/shared/jsonwriter.h>
#include <engine/shared/protocol.h> #include <engine/shared/protocol.h>
#include <game/generated/protocol.h> #include <game/generated/protocol.h>
#include <game/generated/protocol7.h> #include <game/generated/protocol7.h>
@ -365,10 +366,10 @@ public:
/** /**
* Used to report custom player info to master servers. * Used to report custom player info to master servers.
* *
* @param aBuf Should be the json key values to add, starting with a ',' beforehand, like: ',"skin": "default", "team": 1' * @param pJsonWriter A pointer to a CJsonStringWriter which the custom data will be added to.
* @param i The client id. * @param i The client id.
*/ */
virtual void OnUpdatePlayerServerInfo(char *aBuf, int BufSize, int Id) = 0; virtual void OnUpdatePlayerServerInfo(CJsonStringWriter *pJSonWriter, int Id) = 0;
}; };
extern IGameServer *CreateGameServer(); extern IGameServer *CreateGameServer();

View file

@ -24,6 +24,7 @@
#include <engine/shared/host_lookup.h> #include <engine/shared/host_lookup.h>
#include <engine/shared/http.h> #include <engine/shared/http.h>
#include <engine/shared/json.h> #include <engine/shared/json.h>
#include <engine/shared/jsonwriter.h>
#include <engine/shared/masterserver.h> #include <engine/shared/masterserver.h>
#include <engine/shared/netban.h> #include <engine/shared/netban.h>
#include <engine/shared/network.h> #include <engine/shared/network.h>
@ -2315,77 +2316,81 @@ void CServer::UpdateRegisterServerInfo()
int MaxPlayers = maximum(m_NetServer.MaxClients() - maximum(g_Config.m_SvSpectatorSlots, g_Config.m_SvReservedSlots), PlayerCount); int MaxPlayers = maximum(m_NetServer.MaxClients() - maximum(g_Config.m_SvSpectatorSlots, g_Config.m_SvReservedSlots), PlayerCount);
int MaxClients = maximum(m_NetServer.MaxClients() - g_Config.m_SvReservedSlots, ClientCount); int MaxClients = maximum(m_NetServer.MaxClients() - g_Config.m_SvReservedSlots, ClientCount);
char aName[256];
char aGameType[32];
char aMapName[64];
char aVersion[64];
char aMapSha256[SHA256_MAXSTRSIZE]; char aMapSha256[SHA256_MAXSTRSIZE];
sha256_str(m_aCurrentMapSha256[MAP_TYPE_SIX], aMapSha256, sizeof(aMapSha256)); sha256_str(m_aCurrentMapSha256[MAP_TYPE_SIX], aMapSha256, sizeof(aMapSha256));
char aInfo[16384]; CJsonStringWriter JsonWriter;
str_format(aInfo, sizeof(aInfo),
"{" JsonWriter.BeginObject();
"\"max_clients\":%d," JsonWriter.WriteAttribute("max_clients");
"\"max_players\":%d," JsonWriter.WriteIntValue(MaxClients);
"\"passworded\":%s,"
"\"game_type\":\"%s\"," JsonWriter.WriteAttribute("max_players");
"\"name\":\"%s\"," JsonWriter.WriteIntValue(MaxPlayers);
"\"map\":{"
"\"name\":\"%s\"," JsonWriter.WriteAttribute("passworded");
"\"sha256\":\"%s\"," JsonWriter.WriteBoolValue(g_Config.m_Password[0]);
"\"size\":%d"
"}," JsonWriter.WriteAttribute("game_type");
"\"version\":\"%s\"," JsonWriter.WriteStrValue(GameServer()->GameType());
"\"client_score_kind\":\"time\","
"\"requires_login\":false," JsonWriter.WriteAttribute("name");
"\"clients\":[", JsonWriter.WriteStrValue(g_Config.m_SvName);
MaxClients,
MaxPlayers, JsonWriter.WriteAttribute("map");
JsonBool(g_Config.m_Password[0]), JsonWriter.BeginObject();
EscapeJson(aGameType, sizeof(aGameType), GameServer()->GameType()), JsonWriter.WriteAttribute("name");
EscapeJson(aName, sizeof(aName), g_Config.m_SvName), JsonWriter.WriteStrValue(m_aCurrentMap);
EscapeJson(aMapName, sizeof(aMapName), m_aCurrentMap), JsonWriter.WriteAttribute("sha256");
aMapSha256, JsonWriter.WriteStrValue(aMapSha256);
m_aCurrentMapSize[MAP_TYPE_SIX], JsonWriter.WriteAttribute("size");
EscapeJson(aVersion, sizeof(aVersion), GameServer()->Version())); JsonWriter.WriteIntValue(m_aCurrentMapSize[MAP_TYPE_SIX]);
JsonWriter.EndObject();
JsonWriter.WriteAttribute("version");
JsonWriter.WriteStrValue(GameServer()->Version());
JsonWriter.WriteAttribute("client_score_kind");
JsonWriter.WriteStrValue("time"); // "points" or "time"
JsonWriter.WriteAttribute("requires_login");
JsonWriter.WriteBoolValue(false);
JsonWriter.WriteAttribute("clients");
JsonWriter.BeginArray();
bool FirstPlayer = true;
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
{ {
if(m_aClients[i].IncludedInServerInfo()) if(m_aClients[i].IncludedInServerInfo())
{ {
char aCName[32]; JsonWriter.BeginObject();
char aCClan[32];
char aExtraPlayerInfo[512]; JsonWriter.WriteAttribute("name");
GameServer()->OnUpdatePlayerServerInfo(aExtraPlayerInfo, sizeof(aExtraPlayerInfo), i); JsonWriter.WriteStrValue(ClientName(i));
char aClientInfo[1024]; JsonWriter.WriteAttribute("clan");
str_format(aClientInfo, sizeof(aClientInfo), JsonWriter.WriteStrValue(ClientClan(i));
"%s{"
"\"name\":\"%s\"," JsonWriter.WriteAttribute("country");
"\"clan\":\"%s\"," JsonWriter.WriteIntValue(m_aClients[i].m_Country);
"\"country\":%d,"
"\"score\":%d," JsonWriter.WriteAttribute("score");
"\"is_player\":%s" JsonWriter.WriteIntValue(m_aClients[i].m_Score.value_or(-9999));
"%s"
"}", JsonWriter.WriteAttribute("is_player");
!FirstPlayer ? "," : "", JsonWriter.WriteBoolValue(GameServer()->IsClientPlayer(i));
EscapeJson(aCName, sizeof(aCName), ClientName(i)),
EscapeJson(aCClan, sizeof(aCClan), ClientClan(i)), GameServer()->OnUpdatePlayerServerInfo(&JsonWriter, i);
m_aClients[i].m_Country,
m_aClients[i].m_Score.value_or(-9999), JsonWriter.EndObject();
JsonBool(GameServer()->IsClientPlayer(i)),
aExtraPlayerInfo);
str_append(aInfo, aClientInfo);
FirstPlayer = false;
} }
} }
str_append(aInfo, "]}"); JsonWriter.EndArray();
JsonWriter.EndObject();
m_pRegister->OnNewInfo(aInfo); m_pRegister->OnNewInfo(JsonWriter.GetOutputString().c_str());
} }
void CServer::UpdateServerInfo(bool Resend) void CServer::UpdateServerInfo(bool Resend)

View file

@ -4842,78 +4842,61 @@ bool CGameContext::RateLimitPlayerMapVote(int ClientId) const
return false; return false;
} }
void CGameContext::OnUpdatePlayerServerInfo(char *aBuf, int BufSize, int Id) void CGameContext::OnUpdatePlayerServerInfo(CJsonStringWriter *pJSonWriter, int Id)
{ {
if(BufSize <= 0)
return;
aBuf[0] = '\0';
if(!m_apPlayers[Id]) if(!m_apPlayers[Id])
return; return;
char aCSkinName[64];
CTeeInfo &TeeInfo = m_apPlayers[Id]->m_TeeInfos; CTeeInfo &TeeInfo = m_apPlayers[Id]->m_TeeInfos;
char aJsonSkin[400]; pJSonWriter->WriteAttribute("skin");
aJsonSkin[0] = '\0'; pJSonWriter->BeginObject();
// 0.6
if(!Server()->IsSixup(Id)) if(!Server()->IsSixup(Id))
{ {
// 0.6 pJSonWriter->WriteAttribute("name");
pJSonWriter->WriteStrValue(TeeInfo.m_aSkinName);
if(TeeInfo.m_UseCustomColor) if(TeeInfo.m_UseCustomColor)
{ {
str_format(aJsonSkin, sizeof(aJsonSkin), pJSonWriter->WriteAttribute("color_body");
"\"name\":\"%s\"," pJSonWriter->WriteIntValue(TeeInfo.m_ColorBody);
"\"color_body\":%d,"
"\"color_feet\":%d", pJSonWriter->WriteAttribute("color_feet");
EscapeJson(aCSkinName, sizeof(aCSkinName), TeeInfo.m_aSkinName), pJSonWriter->WriteIntValue(TeeInfo.m_ColorFeet);
TeeInfo.m_ColorBody,
TeeInfo.m_ColorFeet);
}
else
{
str_format(aJsonSkin, sizeof(aJsonSkin),
"\"name\":\"%s\"",
EscapeJson(aCSkinName, sizeof(aCSkinName), TeeInfo.m_aSkinName));
} }
} }
// 0.7
else else
{ {
const char *apPartNames[protocol7::NUM_SKINPARTS] = {"body", "marking", "decoration", "hands", "feet", "eyes"}; const char *apPartNames[protocol7::NUM_SKINPARTS] = {"body", "marking", "decoration", "hands", "feet", "eyes"};
char aPartBuf[64];
for(int i = 0; i < protocol7::NUM_SKINPARTS; ++i) for(int i = 0; i < protocol7::NUM_SKINPARTS; ++i)
{ {
str_format(aPartBuf, sizeof(aPartBuf), pJSonWriter->WriteAttribute(apPartNames[i]);
"%s\"%s\":{" pJSonWriter->BeginObject();
"\"name\":\"%s\"",
i == 0 ? "" : ",",
apPartNames[i],
EscapeJson(aCSkinName, sizeof(aCSkinName), TeeInfo.m_apSkinPartNames[i]));
str_append(aJsonSkin, aPartBuf); pJSonWriter->WriteAttribute("name");
pJSonWriter->WriteStrValue(TeeInfo.m_apSkinPartNames[i]);
if(TeeInfo.m_aUseCustomColors[i]) if(TeeInfo.m_aUseCustomColors[i])
{ {
str_format(aPartBuf, sizeof(aPartBuf), pJSonWriter->WriteAttribute("color");
",\"color\":%d", pJSonWriter->WriteIntValue(TeeInfo.m_aSkinPartColors[i]);
TeeInfo.m_aSkinPartColors[i]);
str_append(aJsonSkin, aPartBuf);
} }
str_append(aJsonSkin, "}");
pJSonWriter->EndObject();
} }
} }
pJSonWriter->EndObject();
pJSonWriter->WriteAttribute("afk");
pJSonWriter->WriteBoolValue(m_apPlayers[Id]->IsAfk());
const int Team = m_pController->IsTeamPlay() ? m_apPlayers[Id]->GetTeam() : m_apPlayers[Id]->GetTeam() == TEAM_SPECTATORS ? -1 : GetDDRaceTeam(Id); const int Team = m_pController->IsTeamPlay() ? m_apPlayers[Id]->GetTeam() : m_apPlayers[Id]->GetTeam() == TEAM_SPECTATORS ? -1 : GetDDRaceTeam(Id);
str_format(aBuf, BufSize,
",\"skin\":{" pJSonWriter->WriteAttribute("team");
"%s" pJSonWriter->WriteIntValue(Team);
"},"
"\"afk\":%s,"
"\"team\":%d",
aJsonSkin,
JsonBool(m_apPlayers[Id]->IsAfk()),
Team);
} }

View file

@ -357,7 +357,7 @@ public:
bool RateLimitPlayerVote(int ClientId); bool RateLimitPlayerVote(int ClientId);
bool RateLimitPlayerMapVote(int ClientId) const; bool RateLimitPlayerMapVote(int ClientId) const;
void OnUpdatePlayerServerInfo(char *aBuf, int BufSize, int Id) override; void OnUpdatePlayerServerInfo(CJsonStringWriter *pJSonWriter, int Id) override;
std::shared_ptr<CScoreRandomMapResult> m_SqlRandomMapResult; std::shared_ptr<CScoreRandomMapResult> m_SqlRandomMapResult;