From f897af8dbb987bd28fb65f3be159f6830e6ba514 Mon Sep 17 00:00:00 2001 From: furo Date: Fri, 23 Aug 2024 20:07:11 +0200 Subject: [PATCH] Use `CJsonWriter` for creating server info JSON --- src/engine/server.h | 5 +- src/engine/server/server.cpp | 117 +++++++++++++++++--------------- src/game/server/gamecontext.cpp | 75 ++++++++------------ src/game/server/gamecontext.h | 2 +- 4 files changed, 94 insertions(+), 105 deletions(-) diff --git a/src/engine/server.h b/src/engine/server.h index 64ec543ca..62f9504b8 100644 --- a/src/engine/server.h +++ b/src/engine/server.h @@ -12,6 +12,7 @@ #include "kernel.h" #include "message.h" +#include #include #include #include @@ -365,10 +366,10 @@ public: /** * 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. */ - virtual void OnUpdatePlayerServerInfo(char *aBuf, int BufSize, int Id) = 0; + virtual void OnUpdatePlayerServerInfo(CJsonStringWriter *pJSonWriter, int Id) = 0; }; extern IGameServer *CreateGameServer(); diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index de815e4ac..791953890 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -2315,77 +2316,81 @@ void CServer::UpdateRegisterServerInfo() 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); - char aName[256]; - char aGameType[32]; - char aMapName[64]; - char aVersion[64]; char aMapSha256[SHA256_MAXSTRSIZE]; sha256_str(m_aCurrentMapSha256[MAP_TYPE_SIX], aMapSha256, sizeof(aMapSha256)); - char aInfo[16384]; - str_format(aInfo, sizeof(aInfo), - "{" - "\"max_clients\":%d," - "\"max_players\":%d," - "\"passworded\":%s," - "\"game_type\":\"%s\"," - "\"name\":\"%s\"," - "\"map\":{" - "\"name\":\"%s\"," - "\"sha256\":\"%s\"," - "\"size\":%d" - "}," - "\"version\":\"%s\"," - "\"client_score_kind\":\"time\"," - "\"requires_login\":false," - "\"clients\":[", - MaxClients, - MaxPlayers, - JsonBool(g_Config.m_Password[0]), - EscapeJson(aGameType, sizeof(aGameType), GameServer()->GameType()), - EscapeJson(aName, sizeof(aName), g_Config.m_SvName), - EscapeJson(aMapName, sizeof(aMapName), m_aCurrentMap), - aMapSha256, - m_aCurrentMapSize[MAP_TYPE_SIX], - EscapeJson(aVersion, sizeof(aVersion), GameServer()->Version())); + CJsonStringWriter JsonWriter; + + JsonWriter.BeginObject(); + JsonWriter.WriteAttribute("max_clients"); + JsonWriter.WriteIntValue(MaxClients); + + JsonWriter.WriteAttribute("max_players"); + JsonWriter.WriteIntValue(MaxPlayers); + + JsonWriter.WriteAttribute("passworded"); + JsonWriter.WriteBoolValue(g_Config.m_Password[0]); + + JsonWriter.WriteAttribute("game_type"); + JsonWriter.WriteStrValue(GameServer()->GameType()); + + JsonWriter.WriteAttribute("name"); + JsonWriter.WriteStrValue(g_Config.m_SvName); + + JsonWriter.WriteAttribute("map"); + JsonWriter.BeginObject(); + JsonWriter.WriteAttribute("name"); + JsonWriter.WriteStrValue(m_aCurrentMap); + JsonWriter.WriteAttribute("sha256"); + JsonWriter.WriteStrValue(aMapSha256); + JsonWriter.WriteAttribute("size"); + 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++) { if(m_aClients[i].IncludedInServerInfo()) { - char aCName[32]; - char aCClan[32]; + JsonWriter.BeginObject(); - char aExtraPlayerInfo[512]; - GameServer()->OnUpdatePlayerServerInfo(aExtraPlayerInfo, sizeof(aExtraPlayerInfo), i); + JsonWriter.WriteAttribute("name"); + JsonWriter.WriteStrValue(ClientName(i)); - char aClientInfo[1024]; - str_format(aClientInfo, sizeof(aClientInfo), - "%s{" - "\"name\":\"%s\"," - "\"clan\":\"%s\"," - "\"country\":%d," - "\"score\":%d," - "\"is_player\":%s" - "%s" - "}", - !FirstPlayer ? "," : "", - EscapeJson(aCName, sizeof(aCName), ClientName(i)), - EscapeJson(aCClan, sizeof(aCClan), ClientClan(i)), - m_aClients[i].m_Country, - m_aClients[i].m_Score.value_or(-9999), - JsonBool(GameServer()->IsClientPlayer(i)), - aExtraPlayerInfo); - str_append(aInfo, aClientInfo); - FirstPlayer = false; + JsonWriter.WriteAttribute("clan"); + JsonWriter.WriteStrValue(ClientClan(i)); + + JsonWriter.WriteAttribute("country"); + JsonWriter.WriteIntValue(m_aClients[i].m_Country); + + JsonWriter.WriteAttribute("score"); + JsonWriter.WriteIntValue(m_aClients[i].m_Score.value_or(-9999)); + + JsonWriter.WriteAttribute("is_player"); + JsonWriter.WriteBoolValue(GameServer()->IsClientPlayer(i)); + + GameServer()->OnUpdatePlayerServerInfo(&JsonWriter, i); + + JsonWriter.EndObject(); } } - str_append(aInfo, "]}"); + JsonWriter.EndArray(); + JsonWriter.EndObject(); - m_pRegister->OnNewInfo(aInfo); + m_pRegister->OnNewInfo(JsonWriter.GetOutputString().c_str()); } void CServer::UpdateServerInfo(bool Resend) diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 884ef1e9e..e47f63475 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -4842,78 +4842,61 @@ bool CGameContext::RateLimitPlayerMapVote(int ClientId) const 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]) return; - char aCSkinName[64]; - CTeeInfo &TeeInfo = m_apPlayers[Id]->m_TeeInfos; - char aJsonSkin[400]; - aJsonSkin[0] = '\0'; + pJSonWriter->WriteAttribute("skin"); + pJSonWriter->BeginObject(); + // 0.6 if(!Server()->IsSixup(Id)) { - // 0.6 + pJSonWriter->WriteAttribute("name"); + pJSonWriter->WriteStrValue(TeeInfo.m_aSkinName); + if(TeeInfo.m_UseCustomColor) { - str_format(aJsonSkin, sizeof(aJsonSkin), - "\"name\":\"%s\"," - "\"color_body\":%d," - "\"color_feet\":%d", - EscapeJson(aCSkinName, sizeof(aCSkinName), TeeInfo.m_aSkinName), - TeeInfo.m_ColorBody, - TeeInfo.m_ColorFeet); - } - else - { - str_format(aJsonSkin, sizeof(aJsonSkin), - "\"name\":\"%s\"", - EscapeJson(aCSkinName, sizeof(aCSkinName), TeeInfo.m_aSkinName)); + pJSonWriter->WriteAttribute("color_body"); + pJSonWriter->WriteIntValue(TeeInfo.m_ColorBody); + + pJSonWriter->WriteAttribute("color_feet"); + pJSonWriter->WriteIntValue(TeeInfo.m_ColorFeet); } } + // 0.7 else { const char *apPartNames[protocol7::NUM_SKINPARTS] = {"body", "marking", "decoration", "hands", "feet", "eyes"}; - char aPartBuf[64]; for(int i = 0; i < protocol7::NUM_SKINPARTS; ++i) { - str_format(aPartBuf, sizeof(aPartBuf), - "%s\"%s\":{" - "\"name\":\"%s\"", - i == 0 ? "" : ",", - apPartNames[i], - EscapeJson(aCSkinName, sizeof(aCSkinName), TeeInfo.m_apSkinPartNames[i])); + pJSonWriter->WriteAttribute(apPartNames[i]); + pJSonWriter->BeginObject(); - str_append(aJsonSkin, aPartBuf); + pJSonWriter->WriteAttribute("name"); + pJSonWriter->WriteStrValue(TeeInfo.m_apSkinPartNames[i]); if(TeeInfo.m_aUseCustomColors[i]) { - str_format(aPartBuf, sizeof(aPartBuf), - ",\"color\":%d", - TeeInfo.m_aSkinPartColors[i]); - str_append(aJsonSkin, aPartBuf); + pJSonWriter->WriteAttribute("color"); + pJSonWriter->WriteIntValue(TeeInfo.m_aSkinPartColors[i]); } - 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); - str_format(aBuf, BufSize, - ",\"skin\":{" - "%s" - "}," - "\"afk\":%s," - "\"team\":%d", - aJsonSkin, - JsonBool(m_apPlayers[Id]->IsAfk()), - Team); + + pJSonWriter->WriteAttribute("team"); + pJSonWriter->WriteIntValue(Team); } diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 62e235cae..66db3dc51 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -357,7 +357,7 @@ public: bool RateLimitPlayerVote(int ClientId); bool RateLimitPlayerMapVote(int ClientId) const; - void OnUpdatePlayerServerInfo(char *aBuf, int BufSize, int Id) override; + void OnUpdatePlayerServerInfo(CJsonStringWriter *pJSonWriter, int Id) override; std::shared_ptr m_SqlRandomMapResult;