From 594968fe07458cea5a3a348b2ca9c521eb7c7705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Thu, 8 Aug 2024 21:57:33 +0200 Subject: [PATCH] Improve `cl_show_ids`: support spectator menu, optimize, refactor Also show client IDs in the spectator menu when `cl_show_ids` is enabled. Previously, this setting applied to scoreboard and chat, although the setting and config variable descriptions were only mentioning the scoreboard. Extract client ID formatting in `CGameClient::FormatClientId` function to reduce duplicate code and ensure it is consistent. Correctly indent client IDs also when largest client ID is 100 or larger. Fix scoreboard spectator client ID buffer not being large enough for IDs 100 and larger. Make client ID formatting more efficient by avoiding `str_format` except for formatting the number itself and appending text directly to the text cursor when possible. --- src/engine/shared/config_variables.h | 2 +- src/game/client/components/chat.cpp | 16 ++++------- src/game/client/components/menus_settings.cpp | 15 ++++------ src/game/client/components/scoreboard.cpp | 14 ++++------ src/game/client/components/spectator.cpp | 11 +++++++- src/game/client/gameclient.cpp | 28 +++++++++++++++++++ src/game/client/gameclient.h | 9 ++++++ 7 files changed, 65 insertions(+), 30 deletions(-) diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 417807e84..5396ed233 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -577,7 +577,7 @@ MACRO_CONFIG_COL(ClMessageFriendColor, cl_message_friend_color, 65425, CFGFLAG_C MACRO_CONFIG_INT(ConnTimeout, conn_timeout, 100, 5, 1000, CFGFLAG_SAVE | CFGFLAG_CLIENT | CFGFLAG_SERVER, "Network timeout") MACRO_CONFIG_INT(ConnTimeoutProtection, conn_timeout_protection, 1000, 5, 10000, CFGFLAG_SERVER, "Network timeout protection") -MACRO_CONFIG_INT(ClShowIds, cl_show_ids, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Whether to show client ids in scoreboard") +MACRO_CONFIG_INT(ClShowIds, cl_show_ids, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Whether to show client IDs in scoreboard, chat and spectator menu") MACRO_CONFIG_INT(ClScoreboardOnDeath, cl_scoreboard_on_death, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Whether to show scoreboard after death or not") MACRO_CONFIG_INT(ClAutoRaceRecord, cl_auto_race_record, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Save the best demo of each race") MACRO_CONFIG_INT(ClReplays, cl_replays, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable/disable replays") diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp index b94339dfa..507918d92 100644 --- a/src/game/client/components/chat.cpp +++ b/src/game/client/components/chat.cpp @@ -977,18 +977,12 @@ void CChat::OnPrepareLines(float y) TextRender()->DeleteTextContainer(Line.m_TextContainerIndex); Graphics()->DeleteQuadContainer(Line.m_QuadContainerIndex); - char aName[64 + 12] = ""; - + char aClientId[16] = ""; if(g_Config.m_ClShowIds && Line.m_ClientId >= 0 && Line.m_aName[0] != '\0') { - if(Line.m_ClientId < 10) - str_format(aName, sizeof(aName), " %d: ", Line.m_ClientId); - else - str_format(aName, sizeof(aName), "%d: ", Line.m_ClientId); + GameClient()->FormatClientId(Line.m_ClientId, aClientId, EClientIdFormat::INDENT_AUTO); } - str_append(aName, Line.m_aName); - char aCount[12]; if(Line.m_ClientId < 0) str_format(aCount, sizeof(aCount), "[%d] ", Line.m_TimesRepeated + 1); @@ -1029,7 +1023,8 @@ void CChat::OnPrepareLines(float y) } } - TextRender()->TextEx(&Cursor, aName); + TextRender()->TextEx(&Cursor, aClientId); + TextRender()->TextEx(&Cursor, Line.m_aName); if(Line.m_TimesRepeated > 0) TextRender()->TextEx(&Cursor, aCount); @@ -1099,7 +1094,8 @@ void CChat::OnPrepareLines(float y) NameColor = ColorRGBA(0.8f, 0.8f, 0.8f, 1.f); TextRender()->TextColor(NameColor); - TextRender()->CreateOrAppendTextContainer(Line.m_TextContainerIndex, &Cursor, aName); + TextRender()->CreateOrAppendTextContainer(Line.m_TextContainerIndex, &Cursor, aClientId); + TextRender()->CreateOrAppendTextContainer(Line.m_TextContainerIndex, &Cursor, Line.m_aName); if(Line.m_TimesRepeated > 0) { diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index b22d50ec2..9eff2b3af 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -2544,7 +2544,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView) RightView.HSplitTop(MarginSmall, nullptr, &RightView); // Switches of various DDRace HUD elements - DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowIds, Localize("Show client IDs in scoreboard"), &g_Config.m_ClShowIds, &RightView, LineSize); + DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowIds, Localize("Show client IDs (scoreboard, chat, spectator)"), &g_Config.m_ClShowIds, &RightView, LineSize); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudDDRace, Localize("Show DDRace HUD"), &g_Config.m_ClShowhudDDRace, &RightView, LineSize); if(g_Config.m_ClShowhudDDRace) { @@ -2750,18 +2750,12 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView) LocalCursor.m_LineWidth = LineWidth; const auto &Line = s_vLines[LineIndex]; - char aName[64 + 12] = ""; - + char aClientId[16] = ""; if(g_Config.m_ClShowIds && Line.m_ClientId >= 0 && Line.m_aName[0] != '\0') { - if(Line.m_ClientId < 10) - str_format(aName, sizeof(aName), " %d: ", Line.m_ClientId); - else - str_format(aName, sizeof(aName), "%d: ", Line.m_ClientId); + GameClient()->FormatClientId(Line.m_ClientId, aClientId, EClientIdFormat::INDENT_FORCE); } - str_append(aName, Line.m_aName); - char aCount[12]; if(Line.m_ClientId < 0) str_format(aCount, sizeof(aCount), "[%d] ", Line.m_TimesRepeated + 1); @@ -2793,7 +2787,8 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView) if(Render) TextRender()->TextColor(NameColor); - TextRender()->TextEx(&LocalCursor, aName, -1); + TextRender()->TextEx(&LocalCursor, aClientId); + TextRender()->TextEx(&LocalCursor, Line.m_aName); if(Line.m_TimesRepeated > 0) { diff --git a/src/game/client/components/scoreboard.cpp b/src/game/client/components/scoreboard.cpp index de08db6a8..a08823be6 100644 --- a/src/game/client/components/scoreboard.cpp +++ b/src/game/client/components/scoreboard.cpp @@ -206,8 +206,8 @@ void CScoreboard::RenderSpectators(CUIRect Spectators) if(g_Config.m_ClShowIds) { - char aClientId[5]; - str_format(aClientId, sizeof(aClientId), "%d: ", pInfo->m_ClientId); + char aClientId[16]; + GameClient()->FormatClientId(pInfo->m_ClientId, aClientId, EClientIdFormat::NO_INDENT); TextRender()->TextEx(&Cursor, aClientId); } TextRender()->TextEx(&Cursor, GameClient()->m_aClients[pInfo->m_ClientId].m_aName); @@ -512,13 +512,11 @@ void CScoreboard::RenderScoreboard(CUIRect Scoreboard, int Team, int CountStart, } if(g_Config.m_ClShowIds) { - str_format(aBuf, sizeof(aBuf), "%s%d: %s", pInfo->m_ClientId < 10 ? " " : "", pInfo->m_ClientId, ClientData.m_aName); - TextRender()->TextEx(&Cursor, aBuf); - } - else - { - TextRender()->TextEx(&Cursor, ClientData.m_aName); + char aClientId[16]; + GameClient()->FormatClientId(pInfo->m_ClientId, aClientId, EClientIdFormat::INDENT_AUTO); + TextRender()->TextEx(&Cursor, aClientId); } + TextRender()->TextEx(&Cursor, ClientData.m_aName); // ready / watching if(Client()->IsSixup() && Client()->m_TranslationContext.m_aClients[pInfo->m_ClientId].m_PlayerFlags7 & protocol7::PLAYERFLAG_READY) diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp index 11b4fd383..97b9d955b 100644 --- a/src/game/client/components/spectator.cpp +++ b/src/game/client/components/spectator.cpp @@ -477,7 +477,16 @@ void CSpectator::OnRender() TextRender()->TextColor(1.0f, 1.0f, 1.0f, PlayerSelected ? 1.0f : 0.5f); TeeAlpha = 1.0f; } - TextRender()->Text(Width / 2.0f + x + 50.0f, Height / 2.0f + y + BoxMove + (LineHeight - FontSize) / 2.f, FontSize, m_pClient->m_aClients[m_pClient->m_Snap.m_apInfoByDDTeamName[i]->m_ClientId].m_aName, 220.0f); + CTextCursor NameCursor; + TextRender()->SetCursor(&NameCursor, Width / 2.0f + x + 50.0f, Height / 2.0f + y + BoxMove + (LineHeight - FontSize) / 2.f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_ELLIPSIS_AT_END); + NameCursor.m_LineWidth = 180.0f; + if(g_Config.m_ClShowIds) + { + char aClientId[16]; + GameClient()->FormatClientId(m_pClient->m_Snap.m_apInfoByDDTeamName[i]->m_ClientId, aClientId, EClientIdFormat::INDENT_AUTO); + TextRender()->TextEx(&NameCursor, aClientId); + } + TextRender()->TextEx(&NameCursor, m_pClient->m_aClients[m_pClient->m_Snap.m_apInfoByDDTeamName[i]->m_ClientId].m_aName); if(GameClient()->m_MultiViewActivated) { diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 881ef4f44..34720c90c 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -846,6 +846,32 @@ ColorRGBA CGameClient::GetDDTeamColor(int DDTeam, float Lightness) const return color_cast(ColorHSLA(Hue, 1.0f, Lightness)); } +void CGameClient::FormatClientId(int ClientId, char (&aClientId)[16], EClientIdFormat Format) const +{ + if(Format == EClientIdFormat::NO_INDENT) + { + str_format(aClientId, sizeof(aClientId), "%d", ClientId); + } + else + { + const int HighestClientId = Format == EClientIdFormat::INDENT_AUTO ? m_Snap.m_HighestClientId : 64; + const char *pFigureSpace = " "; + char aNumber[8]; + str_format(aNumber, sizeof(aNumber), "%d", ClientId); + aClientId[0] = '\0'; + if(ClientId < 100 && HighestClientId >= 100) + { + str_append(aClientId, pFigureSpace); + } + if(ClientId < 10 && HighestClientId >= 10) + { + str_append(aClientId, pFigureSpace); + } + str_append(aClientId, aNumber); + } + str_append(aClientId, ": "); +} + void CGameClient::OnRelease() { // release all systems @@ -1515,6 +1541,8 @@ void CGameClient::OnNewSnapshot() } } + m_Snap.m_HighestClientId = maximum(m_Snap.m_HighestClientId, pInfo->m_ClientId); + // calculate team-balance if(pInfo->m_Team != TEAM_SPECTATORS) { diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 60aa7f4e0..1def52441 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -111,6 +111,13 @@ public: const CNetObj_EntityEx *m_pDataEx; }; +enum class EClientIdFormat +{ + NO_INDENT, + INDENT_AUTO, + INDENT_FORCE, // for rendering settings preview +}; + class CGameClient : public IGameClient { public: @@ -315,6 +322,7 @@ public: int m_LocalClientId; int m_NumPlayers; int m_aTeamSize[2]; + int m_HighestClientId; // spectate data struct CSpectateInfo @@ -575,6 +583,7 @@ public: bool PredictDummy() { return g_Config.m_ClPredictDummy && Client()->DummyConnected() && m_Snap.m_LocalClientId >= 0 && m_PredictedDummyId >= 0 && !m_aClients[m_PredictedDummyId].m_Paused; } const CTuningParams *GetTuning(int i) { return &m_aTuningList[i]; } ColorRGBA GetDDTeamColor(int DDTeam, float Lightness = 0.5f) const; + void FormatClientId(int ClientId, char (&aClientId)[16], EClientIdFormat Format) const; CGameWorld m_GameWorld; CGameWorld m_PredictedWorld;