From dd2a3b8d5f3c2f0b56381be1530b1795f4db342c Mon Sep 17 00:00:00 2001 From: +KZ Date: Thu, 1 Jan 2026 12:15:29 -0300 Subject: [PATCH 1/7] Identify clients (From Kaizo Network) --- CMakeLists.txt | 3 + data/clienticons/duckicon.png | Bin 0 -> 4423 bytes data/clienticons/kaizoicon.png | Bin 0 -> 19271 bytes data/clienticons/license.txt | 3 + datasrc/content.py | 16 ++ .../external/ddnet-custom-clients/README.md | 17 ++ .../ddnet-custom-clients/custom_clients_ids.h | 20 +++ .../external/ddnet-custom-clients/license.txt | 165 ++++++++++++++++++ src/engine/shared/config_variables.h | 4 + src/game/client/components/nameplates.cpp | 44 +++++ src/game/client/gameclient.cpp | 122 ++++++++++++- src/game/client/gameclient.h | 15 ++ 12 files changed, 404 insertions(+), 5 deletions(-) create mode 100644 data/clienticons/duckicon.png create mode 100644 data/clienticons/kaizoicon.png create mode 100644 data/clienticons/license.txt create mode 100644 src/engine/external/ddnet-custom-clients/README.md create mode 100644 src/engine/external/ddnet-custom-clients/custom_clients_ids.h create mode 100644 src/engine/external/ddnet-custom-clients/license.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index b26fa98fbab..3681fa5d6c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1847,6 +1847,9 @@ set(EXPECTED_DATA skins7/x_ninja.json skins7/xmas_hat.png strong_weak.png + clienticons/duckicon.png + clienticons/kaizoicon.png + clienticons/license.txt themes/auto.png themes/autumn.png themes/autumn_day.map diff --git a/data/clienticons/duckicon.png b/data/clienticons/duckicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c75743dd4f800f1ea283e680be1663054856b161 GIT binary patch literal 4423 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 N002ovPDHLkV1g^=LO1{b literal 0 HcmV?d00001 diff --git a/data/clienticons/kaizoicon.png b/data/clienticons/kaizoicon.png new file mode 100644 index 0000000000000000000000000000000000000000..9ab866d01cc11ab258dde3ae40025881c25880c5 GIT binary patch literal 19271 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 aT1#O9+VNScBJcxQD2j5bvc*qK-~2Bc33F8d literal 0 HcmV?d00001 diff --git a/data/clienticons/license.txt b/data/clienticons/license.txt new file mode 100644 index 00000000000..7f708b28846 --- /dev/null +++ b/data/clienticons/license.txt @@ -0,0 +1,3 @@ +Licenses for the files inside this folder: + +kaizoicon.png by +KZ, released under CC BY-SA 4.0 diff --git a/datasrc/content.py b/datasrc/content.py index 9e68d861a16..af3c5e58774 100644 --- a/datasrc/content.py +++ b/datasrc/content.py @@ -492,6 +492,22 @@ def FileList(fmt, num): container.sprites.Add(Sprite("part_pulley", set_extras, 4,0,1,1)) container.sprites.Add(Sprite("part_hectagon", set_extras, 6,0,2,2)) +# TClient Client Icons + +# Kaizo Network +kz_image_kaizoicon= Image("kz_kaizoicon", "clienticons/kaizoicon.png") +container.images.Add(kz_image_kaizoicon) +set_kz_kaizoicon = SpriteSet("kz_kaizoicon", kz_image_kaizoicon, 1, 1) +container.spritesets.Add(set_kz_kaizoicon) +container.sprites.Add(Sprite("kz_kaizoicon", set_kz_kaizoicon, 0, 0, 1, 1)) + +# DuckClient +duck_image_duckicon= Image("duck_duckicon", "clienticons/duckicon.png") +container.images.Add(duck_image_duckicon) +set_duck_duckicon = SpriteSet("duck_duckicon", duck_image_duckicon, 1, 1) +container.spritesets.Add(set_duck_duckicon) +container.sprites.Add(Sprite("duck_duckicon", set_duck_duckicon, 0, 0, 1, 1)) + anim = Animation("base") anim.body.frames.Add(AnimKeyframe(0, 0, -4, 0)) anim.back_foot.frames.Add(AnimKeyframe(0, 0, 10, 0)) diff --git a/src/engine/external/ddnet-custom-clients/README.md b/src/engine/external/ddnet-custom-clients/README.md new file mode 100644 index 00000000000..db9e82e4058 --- /dev/null +++ b/src/engine/external/ddnet-custom-clients/README.md @@ -0,0 +1,17 @@ +# ddnet-custom-clients +Custom clients IDs for DDNet so custom clients can identify which client is each player using by checking invalid country flags + +First implemented in Kaizo Network, but it can also be shared among other clients + +Clients using this: + +* [Kaizo Network](https://github.com/M0REKZ/kaizo-network) +* [Chillerbot-UX](https://github.com/chillerbot/chillerbot-ux) + +# Adding a new client + +When adding a new client ID, make sure the ID number is greater than the ID for Kaizo Network, this way we avoid conflicts with possible future DDNet country flag additions. + +# How to use + +TODO diff --git a/src/engine/external/ddnet-custom-clients/custom_clients_ids.h b/src/engine/external/ddnet-custom-clients/custom_clients_ids.h new file mode 100644 index 00000000000..a23785eff26 --- /dev/null +++ b/src/engine/external/ddnet-custom-clients/custom_clients_ids.h @@ -0,0 +1,20 @@ +// This file can be included several times. +#pragma once + +// Copyright (C) Benjamín Gajardo (also known as +KZ) + +enum +{ + // Custom client IDs + CUSTOM_CLIENT_ID_KAIZO_NETWORK = 16777216, + CUSTOM_CLIENT_ID_PDUCKCLIENT = 16777217, + CUSTOM_CLIENT_ID_CHILLERBOTUX = 33554432, + + //Range is big enough (16777215 possible IDs in between) + MINIMUM_CUSTOM_CLIENT_ID = CUSTOM_CLIENT_ID_KAIZO_NETWORK, + MAXIMUM_CUSTOM_CLIENT_ID = CUSTOM_CLIENT_ID_CHILLERBOTUX, + + // Other info to be shared among clients + CUSTOM_CLIENT_ISDUMMY = 33554433, + CUSTOM_CLIENT_ISBOT = 33554434, // intended for clients like discord bridge bots +}; diff --git a/src/engine/external/ddnet-custom-clients/license.txt b/src/engine/external/ddnet-custom-clients/license.txt new file mode 100644 index 00000000000..0a041280bd0 --- /dev/null +++ b/src/engine/external/ddnet-custom-clients/license.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 6f0c4c60e1b..225fbc998cf 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -756,6 +756,10 @@ MACRO_CONFIG_INT(ClScoreboardStyle, cl_scoreboard_style, 0, 0, 10, CFGFLAG_CLIEN MACRO_CONFIG_INT(ClScoreboardShorten, cl_scoreboard_shorten, 0, 0, 2, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Shorten the scoreboard if there are not so many players") MACRO_CONFIG_INT(ClStatboardWeaponsStyle, cl_statboard_weapons_style, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Change the statboard weapons style to a bar") +// Client identify (from Kaizo Network) +MACRO_CONFIG_INT(ClSendClientType, cl_send_client_type, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Let know other clients that we are DuckClient") +MACRO_CONFIG_INT(ClShowClientType, cl_show_client_type, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Try to identify and show other players clients as icons") + MACRO_CONFIG_INT(ClWeatherSnow, cl_weather_snow, 0, 0, 15, CFGFLAG_CLIENT, "Whether to spawn snow") MACRO_CONFIG_INT(ClUIWidth, cl_ui_width, 600, 400, 1000, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Size of UI (low values may break some UI, might need restart)") MACRO_CONFIG_COL(UiColorButtons, ui_color_buttons, 0xFFFFFFFF, CFGFLAG_CLIENT | CFGFLAG_SAVE | CFGFLAG_COLALPHA, "Interface buttons color") // 160 70 175 228 hasalpha diff --git a/src/game/client/components/nameplates.cpp b/src/game/client/components/nameplates.cpp index 8803bc38c40..153c54fed43 100644 --- a/src/game/client/components/nameplates.cpp +++ b/src/game/client/components/nameplates.cpp @@ -14,6 +14,8 @@ #include #include +#include //TClient + static constexpr float DEFAULT_PADDING = 5.0f; // Part Types @@ -441,6 +443,46 @@ class CNamePlatePartHookStrongWeakId : public CNamePlatePartText CNamePlatePartText(This) {} }; +class CNamePlatePartCustomClient : public CNamePlatePartSprite +{ +public: + void Update(CGameClient &This, const CNamePlateData &Data) override + { + if(!g_Config.m_ClShowClientType || Data.m_ClientId == This.m_Snap.m_LocalClientId) + { + m_Visible = false; + return; + } + + if(This.m_aClients[Data.m_ClientId].m_CustomClient == CUSTOM_CLIENT_ID_KAIZO_NETWORK) + { + m_Texture = g_pData->m_aImages[IMAGE_KZ_KAIZOICON].m_Id; + m_Sprite = SPRITE_KZ_KAIZOICON; + m_Visible = true; + } + else if(This.m_aClients[Data.m_ClientId].m_CustomClient == CUSTOM_CLIENT_ID_PDUCKCLIENT) + { + m_Texture = g_pData->m_aImages[IMAGE_DUCK_DUCKICON].m_Id; + m_Sprite = SPRITE_DUCK_DUCKICON; + m_Visible = true; + } + else + { + m_Visible = false; + } + m_Color.a = Data.m_Color.a; + } + + CNamePlatePartCustomClient(CGameClient &This) : + CNamePlatePartSprite(This) + { + m_Texture = g_pData->m_aImages[IMAGE_KZ_KAIZOICON].m_Id; + m_Padding = vec2(0.0f, 0.0f); + m_Sprite = SPRITE_KZ_KAIZOICON; + m_Size = vec2(20 + DEFAULT_PADDING, 20 + DEFAULT_PADDING); + } +}; + // Name Plates class CNamePlate @@ -496,6 +538,8 @@ class CNamePlate AddPart(This); AddPart(This); + + AddPart(This); } public: diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index b96f343e2ef..d06cbdb16c4 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -86,6 +86,8 @@ #include +#include + using namespace std::chrono_literals; const char *CGameClient::Version() const { return GAME_VERSION; } @@ -514,6 +516,8 @@ void CGameClient::OnUpdate() { pComponent->OnUpdate(); } + + OnKZUpdate(); } void CGameClient::OnDummySwap() @@ -600,6 +604,7 @@ void CGameClient::OnConnected() pComponent->OnMapLoad(); pComponent->OnReset(); } + OnKZReset(); ConfigManager()->ResetGameSettings(); LoadMapSettings(); @@ -728,6 +733,8 @@ void CGameClient::OnReset() for(auto &pComponent : m_vpAll) pComponent->OnReset(); + OnKZReset(); + Editor()->ResetMentions(); Editor()->ResetIngameMoved(); @@ -1251,6 +1258,7 @@ void CGameClient::OnStateChange(int NewState, int OldState) // reset everything when not already connected (to keep gathered stuff) if(NewState < IClient::STATE_ONLINE) OnReset(); + OnKZReset(); // then change the state for(auto &pComponent : m_vpAll) @@ -1748,6 +1756,7 @@ void CGameClient::OnNewSnapshot() } IntsToStr(pInfo->m_aClan, std::size(pInfo->m_aClan), pClient->m_aClan, std::size(pClient->m_aClan)); pClient->m_Country = pInfo->m_Country; + HandleClientCountry(pClient->m_Country, ClientId); //+KZ IntsToStr(pInfo->m_aSkin, std::size(pInfo->m_aSkin), pClient->m_aSkinName, std::size(pClient->m_aSkinName)); if(!CSkin::IsValidName(pClient->m_aSkinName) || @@ -3061,7 +3070,7 @@ void CGameClient::SendStartInfo7(bool Dummy) protocol7::CNetMsg_Cl_StartInfo Msg; Msg.m_pName = Dummy ? Client()->DummyName() : Client()->PlayerName(); Msg.m_pClan = Dummy ? Config()->m_ClDummyClan : Config()->m_PlayerClan; - Msg.m_Country = Dummy ? Config()->m_ClDummyCountry : Config()->m_PlayerCountry; + Msg.m_Country = ReplaceCountryFlagWithCustomClientId(Dummy ? Config()->m_ClDummyCountry : Config()->m_PlayerCountry); for(int p = 0; p < protocol7::NUM_SKINPARTS; p++) { Msg.m_apSkinPartNames[p] = CSkins7::ms_apSkinVariables[(int)Dummy][p]; @@ -3146,7 +3155,7 @@ void CGameClient::SendInfo(bool Start) CNetMsg_Cl_StartInfo Msg; Msg.m_pName = Client()->PlayerName(); Msg.m_pClan = g_Config.m_PlayerClan; - Msg.m_Country = g_Config.m_PlayerCountry; + Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_PlayerCountry); Msg.m_pSkin = g_Config.m_ClPlayerSkin; Msg.m_UseCustomColor = g_Config.m_ClPlayerUseCustomColor; Msg.m_ColorBody = g_Config.m_ClPlayerColorBody; @@ -3161,7 +3170,7 @@ void CGameClient::SendInfo(bool Start) CNetMsg_Cl_ChangeInfo Msg; Msg.m_pName = Client()->PlayerName(); Msg.m_pClan = g_Config.m_PlayerClan; - Msg.m_Country = g_Config.m_PlayerCountry; + Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_PlayerCountry); Msg.m_pSkin = g_Config.m_ClPlayerSkin; Msg.m_UseCustomColor = g_Config.m_ClPlayerUseCustomColor; Msg.m_ColorBody = g_Config.m_ClPlayerColorBody; @@ -3188,7 +3197,7 @@ void CGameClient::SendDummyInfo(bool Start) CNetMsg_Cl_StartInfo Msg; Msg.m_pName = Client()->DummyName(); Msg.m_pClan = g_Config.m_ClDummyClan; - Msg.m_Country = g_Config.m_ClDummyCountry; + Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_ClDummyCountry); Msg.m_pSkin = g_Config.m_ClDummySkin; Msg.m_UseCustomColor = g_Config.m_ClDummyUseCustomColor; Msg.m_ColorBody = g_Config.m_ClDummyColorBody; @@ -3203,7 +3212,7 @@ void CGameClient::SendDummyInfo(bool Start) CNetMsg_Cl_ChangeInfo Msg; Msg.m_pName = Client()->DummyName(); Msg.m_pClan = g_Config.m_ClDummyClan; - Msg.m_Country = g_Config.m_ClDummyCountry; + Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_ClDummyCountry); Msg.m_pSkin = g_Config.m_ClDummySkin; Msg.m_UseCustomColor = g_Config.m_ClDummyUseCustomColor; Msg.m_ColorBody = g_Config.m_ClDummyColorBody; @@ -5354,3 +5363,106 @@ int CGameClient::FindFirstMultiViewId() } return ClientId; } + +void CGameClient::OnKZUpdate() +{ + bool MustSendCustomClient = false; + + for(auto &Client : m_aClients) + { + if(Client.m_Active) + { + if(Client.ClientId() == m_Snap.m_LocalClientId || Client.ClientId() == GetPredictedDummyId()) + { + m_aClients[Client.ClientId()].m_CustomClient = CUSTOM_CLIENT_ID_PDUCKCLIENT; //force tater client for us + } + + if(!m_aClients[Client.ClientId()].m_SentCustomClient) + { + MustSendCustomClient = true; + m_aClients[Client.ClientId()].m_SentCustomClient = true; + } + } + else + { + m_aClients[Client.ClientId()].m_SentCustomClient = false; + } + } + + if(MustSendCustomClient) + { + m_SendingCustomClientTicks = 25; + } + + switch(m_SendingCustomClientTicks) + { + case 25: + SendInfo(false); + SendDummyInfo(false); + m_SendingCustomClientTicks = 24; + break; + case 0: + SendInfo(false); + SendDummyInfo(false); + m_SendingCustomClientTicks = -1; + break; + default: + if(m_SendingCustomClientTicks > 0) + m_SendingCustomClientTicks--; + break; + } +} + +void CGameClient::OnKZReset() +{ + for(auto &ClientData : m_aClients) + { + ClientData.KZReset(); + } + + m_SendingCustomClientTicks = 25; +} + +void CGameClient::CClientData::KZReset() +{ + m_CustomClient = 0; + m_SentCustomClient = false; +} + +// function originally from Kaizo Network by +KZ, credit if used +int CGameClient::ReplaceCountryFlagWithCustomClientId(int Country) +{ + if(!g_Config.m_ClSendClientType) + return Country; + + if(m_SendingCustomClientTicks <= 1) //dont send custom flag + return Country; + + //if some random day amount of flags conflicts with invalid flag, just send normal country + if(m_CountryFlags.Num() >= MINIMUM_CUSTOM_CLIENT_ID) + { + return Country; + } + + return CUSTOM_CLIENT_ID_PDUCKCLIENT; +} + +// function originally from Kaizo Network by +KZ, credit if used +bool CGameClient::IsCustomClientId(int Country) +{ + return (size_t)Country > m_CountryFlags.Num(); +} + +// code originally from Kaizo Network by +KZ, credit if used +int CGameClient::HandleClientCountry(int Country, int ClientId) +{ + if(IsCustomClientId(Country)) //if it is a custom client id, set custom client id and keep country + { + m_aClients[ClientId].m_CustomClient = Country; + return m_aClients[ClientId].m_Country; + } + else //otherwise, set country + { + return Country; + } +} diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 47ff196c03f..6cbb88a05ca 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -551,6 +551,11 @@ class CGameClient : public IGameClient // 0.7 Skin CSixup m_aSixup[NUM_DUMMIES]; + + int m_CustomClient = '\0'; + bool m_SentCustomClient = false; + + void KZReset(); }; CClientData m_aClients[MAX_CLIENTS]; @@ -937,6 +942,7 @@ class CGameClient : public IGameClient void ResetMultiView(); int FindFirstMultiViewId(); + void OnKZUpdate(); void CleanMultiViewId(int ClientId); private: @@ -1003,6 +1009,15 @@ class CGameClient : public IGameClient }; SMultiView m_MultiView; + +public: + void OnKZReset(); + + int ReplaceCountryFlagWithCustomClientId(int Country); + bool IsCustomClientId(int Country); + int m_SendingCustomClientTicks = -1; + int HandleClientCountry(int Country, int ClientId); + int GetPredictedDummyId() { return m_PredictedDummyId; } }; ColorRGBA CalculateNameColor(ColorHSLA TextColorHSL); From 82edd9ddcb46a77c0af9e7c44ab2f3d265e32e50 Mon Sep 17 00:00:00 2001 From: +KZ Date: Thu, 1 Jan 2026 13:00:33 -0300 Subject: [PATCH 2/7] fix --- src/game/client/gameclient.cpp | 46 +++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index d06cbdb16c4..40f0f8ead03 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -5394,23 +5394,32 @@ void CGameClient::OnKZUpdate() m_SendingCustomClientTicks = 25; } - switch(m_SendingCustomClientTicks) - { - case 25: - SendInfo(false); - SendDummyInfo(false); - m_SendingCustomClientTicks = 24; - break; - case 0: - SendInfo(false); - SendDummyInfo(false); - m_SendingCustomClientTicks = -1; - break; - default: - if(m_SendingCustomClientTicks > 0) - m_SendingCustomClientTicks--; - break; - } + switch (m_SendingCustomClientTicks) + { + case 25: + SendInfo(false); + if(m_aClients[m_aLocalIds[0]].m_Country >= MINIMUM_CUSTOM_CLIENT_ID) + m_SendingCustomClientTicks = 24; + break; + case 24: + SendDummyInfo(false); + if(Client()->DummyConnected() ? m_aClients[m_aLocalIds[1]].m_Country >= MINIMUM_CUSTOM_CLIENT_ID : true) + m_SendingCustomClientTicks = 23; + break; + case 1: + SendInfo(false); + if(m_aClients[m_aLocalIds[0]].m_Country < MINIMUM_CUSTOM_CLIENT_ID) + m_SendingCustomClientTicks = 0; + case 0: + SendDummyInfo(false); + if(Client()->DummyConnected() ? m_aClients[m_aLocalIds[1]].m_Country < MINIMUM_CUSTOM_CLIENT_ID : true) + m_SendingCustomClientTicks = -1; + break; + default: + if(m_SendingCustomClientTicks > 0) + m_SendingCustomClientTicks--; + break; + } } void CGameClient::OnKZReset() @@ -5458,7 +5467,8 @@ int CGameClient::HandleClientCountry(int Country, int ClientId) { if(IsCustomClientId(Country)) //if it is a custom client id, set custom client id and keep country { - m_aClients[ClientId].m_CustomClient = Country; + if(!m_aClients[ClientId].m_CustomClient) + m_aClients[ClientId].m_CustomClient = Country; return m_aClients[ClientId].m_Country; } else //otherwise, set country From bb10ad140459750f20582749b52937db2b97ba34 Mon Sep 17 00:00:00 2001 From: Pointer31 Date: Fri, 2 Jan 2026 16:52:11 +0100 Subject: [PATCH 3/7] add send client type settings to DuckC page --- src/game/client/components/menus_settings.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 2cfabd67149..c0f013984b4 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -400,6 +400,23 @@ void CMenus::RenderSettingsDuckClient(CUIRect MainView) str_copy(g_Config.m_TcCustomCommunitiesUrl, "https://raw.githubusercontent.com/SollyBunny/ddnet-custom-communities/refs/heads/main/custom-communities-ddnet-info.json"); } } + + // From Kaizo client + { + // headline + Menu.HSplitTop(30.0f, &Label, &Menu); + Ui()->DoLabel(&Label, Localize("From Kaizo Client"), 20.0f, TEXTALIGN_ML); + + Menu.HSplitTop(VerticalSpacing, nullptr, &Menu); + Menu.HSplitTop(20.0f, &Button, &Menu); + if(DoButton_CheckBox(&g_Config.m_ClSendClientType, Localize("Send Client Type"), g_Config.m_ClSendClientType, &Button)) + g_Config.m_ClSendClientType ^= 1; + + Menu.HSplitTop(VerticalSpacing, nullptr, &Menu); + Menu.HSplitTop(20.0f, &Button, &Menu); + if(DoButton_CheckBox(&g_Config.m_ClShowClientType, Localize("Show Client Types"), g_Config.m_ClShowClientType, &Button)) + g_Config.m_ClShowClientType ^= 1; + } } void CMenus::SetNeedSendInfo() From 9e7fcd9a4af833d43c6e6a5a2e565a4c215839ef Mon Sep 17 00:00:00 2001 From: +KZ <60852359+M0REKZ@users.noreply.github.com> Date: Sat, 7 Feb 2026 16:43:49 -0300 Subject: [PATCH 4/7] Use new way of identifying clients --- .../ddnet-custom-clients/custom_clients_ids.h | 18 ++- src/game/client/gameclient.cpp | 127 +++++++----------- src/game/client/gameclient.h | 6 +- 3 files changed, 66 insertions(+), 85 deletions(-) diff --git a/src/engine/external/ddnet-custom-clients/custom_clients_ids.h b/src/engine/external/ddnet-custom-clients/custom_clients_ids.h index a23785eff26..75eee836d36 100644 --- a/src/engine/external/ddnet-custom-clients/custom_clients_ids.h +++ b/src/engine/external/ddnet-custom-clients/custom_clients_ids.h @@ -5,16 +5,26 @@ enum { - // Custom client IDs + // Custom client IDs (Country flag method) CUSTOM_CLIENT_ID_KAIZO_NETWORK = 16777216, CUSTOM_CLIENT_ID_PDUCKCLIENT = 16777217, + CUSTOM_CLIENT_ID_GAMER_07 = 16777218, //0.7 Client Reserved + CUSTOM_CLIENT_ID_ZILLYWOODS_07 = 16777219, //0.7 Client Reserved + CUSTOM_CLIENT_ID_FCLIENT_07 = 16777220, //0.7 Client Reserved CUSTOM_CLIENT_ID_CHILLERBOTUX = 33554432, //Range is big enough (16777215 possible IDs in between) MINIMUM_CUSTOM_CLIENT_ID = CUSTOM_CLIENT_ID_KAIZO_NETWORK, MAXIMUM_CUSTOM_CLIENT_ID = CUSTOM_CLIENT_ID_CHILLERBOTUX, - // Other info to be shared among clients - CUSTOM_CLIENT_ISDUMMY = 33554433, - CUSTOM_CLIENT_ISBOT = 33554434, // intended for clients like discord bridge bots + // Custom client IDs (Skin Color Method) + // Range is small (510 possible IDs) + + // Body + CCID_COLOR_BODY_KAIZO_CLIENT = 1, + CCID_COLOR_BODY_PDUCKCLIENT = 2, + CCID_COLOR_BODY_CHILLERBOTUX = 3, + + // Feet + // (Empty...) }; diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 40f0f8ead03..ad08b0076c1 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -1771,6 +1771,28 @@ void CGameClient::OnNewSnapshot() if (g_Config.m_ClDuckFilter) str_copy(pClient->m_aSkinName, "Scrubby Duck"); + + //identify kaizo + union + { + int c = 0; + unsigned char b[4]; + } a; + + a.c = pInfo->m_ColorBody; + + if(a.b[3] == CCID_COLOR_BODY_KAIZO_CLIENT) + { + pClient->m_CustomClient = CUSTOM_CLIENT_ID_KAIZO_NETWORK; + } + else if(a.b[3] == CCID_COLOR_BODY_CHILLERBOTUX) + { + pClient->m_CustomClient = CUSTOM_CLIENT_ID_CHILLERBOTUX; + } + else if(a.b[3] == CCID_COLOR_BODY_PDUCKCLIENT) + { + pClient->m_CustomClient = CUSTOM_CLIENT_ID_PDUCKCLIENT; + } } } else if(Item.m_Type == NETOBJTYPE_PLAYERINFO) @@ -3070,7 +3092,7 @@ void CGameClient::SendStartInfo7(bool Dummy) protocol7::CNetMsg_Cl_StartInfo Msg; Msg.m_pName = Dummy ? Client()->DummyName() : Client()->PlayerName(); Msg.m_pClan = Dummy ? Config()->m_ClDummyClan : Config()->m_PlayerClan; - Msg.m_Country = ReplaceCountryFlagWithCustomClientId(Dummy ? Config()->m_ClDummyCountry : Config()->m_PlayerCountry); + Msg.m_Country = Dummy ? Config()->m_ClDummyCountry : Config()->m_PlayerCountry; for(int p = 0; p < protocol7::NUM_SKINPARTS; p++) { Msg.m_apSkinPartNames[p] = CSkins7::ms_apSkinVariables[(int)Dummy][p]; @@ -3155,10 +3177,10 @@ void CGameClient::SendInfo(bool Start) CNetMsg_Cl_StartInfo Msg; Msg.m_pName = Client()->PlayerName(); Msg.m_pClan = g_Config.m_PlayerClan; - Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_PlayerCountry); + Msg.m_Country = g_Config.m_PlayerCountry; Msg.m_pSkin = g_Config.m_ClPlayerSkin; Msg.m_UseCustomColor = g_Config.m_ClPlayerUseCustomColor; - Msg.m_ColorBody = g_Config.m_ClPlayerColorBody; + Msg.m_ColorBody = InsertCustomClientIdIntoSkinColor(g_Config.m_ClPlayerColorBody); Msg.m_ColorFeet = g_Config.m_ClPlayerColorFeet; CMsgPacker Packer(&Msg); Msg.Pack(&Packer); @@ -3170,10 +3192,10 @@ void CGameClient::SendInfo(bool Start) CNetMsg_Cl_ChangeInfo Msg; Msg.m_pName = Client()->PlayerName(); Msg.m_pClan = g_Config.m_PlayerClan; - Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_PlayerCountry); + Msg.m_Country = g_Config.m_PlayerCountry; Msg.m_pSkin = g_Config.m_ClPlayerSkin; Msg.m_UseCustomColor = g_Config.m_ClPlayerUseCustomColor; - Msg.m_ColorBody = g_Config.m_ClPlayerColorBody; + Msg.m_ColorBody = InsertCustomClientIdIntoSkinColor(g_Config.m_ClPlayerColorBody); Msg.m_ColorFeet = g_Config.m_ClPlayerColorFeet; CMsgPacker Packer(&Msg); Msg.Pack(&Packer); @@ -3197,10 +3219,10 @@ void CGameClient::SendDummyInfo(bool Start) CNetMsg_Cl_StartInfo Msg; Msg.m_pName = Client()->DummyName(); Msg.m_pClan = g_Config.m_ClDummyClan; - Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_ClDummyCountry); + Msg.m_Country = g_Config.m_ClDummyCountry; Msg.m_pSkin = g_Config.m_ClDummySkin; Msg.m_UseCustomColor = g_Config.m_ClDummyUseCustomColor; - Msg.m_ColorBody = g_Config.m_ClDummyColorBody; + Msg.m_ColorBody = InsertCustomClientIdIntoSkinColor(g_Config.m_ClDummyColorBody); Msg.m_ColorFeet = g_Config.m_ClDummyColorFeet; CMsgPacker Packer(&Msg); Msg.Pack(&Packer); @@ -3212,10 +3234,10 @@ void CGameClient::SendDummyInfo(bool Start) CNetMsg_Cl_ChangeInfo Msg; Msg.m_pName = Client()->DummyName(); Msg.m_pClan = g_Config.m_ClDummyClan; - Msg.m_Country = ReplaceCountryFlagWithCustomClientId(g_Config.m_ClDummyCountry); + Msg.m_Country = g_Config.m_ClDummyCountry; Msg.m_pSkin = g_Config.m_ClDummySkin; Msg.m_UseCustomColor = g_Config.m_ClDummyUseCustomColor; - Msg.m_ColorBody = g_Config.m_ClDummyColorBody; + Msg.m_ColorBody = InsertCustomClientIdIntoSkinColor(g_Config.m_ClDummyColorBody); Msg.m_ColorFeet = g_Config.m_ClDummyColorFeet; CMsgPacker Packer(&Msg); Msg.Pack(&Packer); @@ -5366,60 +5388,7 @@ int CGameClient::FindFirstMultiViewId() void CGameClient::OnKZUpdate() { - bool MustSendCustomClient = false; - - for(auto &Client : m_aClients) - { - if(Client.m_Active) - { - if(Client.ClientId() == m_Snap.m_LocalClientId || Client.ClientId() == GetPredictedDummyId()) - { - m_aClients[Client.ClientId()].m_CustomClient = CUSTOM_CLIENT_ID_PDUCKCLIENT; //force tater client for us - } - - if(!m_aClients[Client.ClientId()].m_SentCustomClient) - { - MustSendCustomClient = true; - m_aClients[Client.ClientId()].m_SentCustomClient = true; - } - } - else - { - m_aClients[Client.ClientId()].m_SentCustomClient = false; - } - } - - if(MustSendCustomClient) - { - m_SendingCustomClientTicks = 25; - } - - switch (m_SendingCustomClientTicks) - { - case 25: - SendInfo(false); - if(m_aClients[m_aLocalIds[0]].m_Country >= MINIMUM_CUSTOM_CLIENT_ID) - m_SendingCustomClientTicks = 24; - break; - case 24: - SendDummyInfo(false); - if(Client()->DummyConnected() ? m_aClients[m_aLocalIds[1]].m_Country >= MINIMUM_CUSTOM_CLIENT_ID : true) - m_SendingCustomClientTicks = 23; - break; - case 1: - SendInfo(false); - if(m_aClients[m_aLocalIds[0]].m_Country < MINIMUM_CUSTOM_CLIENT_ID) - m_SendingCustomClientTicks = 0; - case 0: - SendDummyInfo(false); - if(Client()->DummyConnected() ? m_aClients[m_aLocalIds[1]].m_Country < MINIMUM_CUSTOM_CLIENT_ID : true) - m_SendingCustomClientTicks = -1; - break; - default: - if(m_SendingCustomClientTicks > 0) - m_SendingCustomClientTicks--; - break; - } + } void CGameClient::OnKZReset() @@ -5428,32 +5397,36 @@ void CGameClient::OnKZReset() { ClientData.KZReset(); } - - m_SendingCustomClientTicks = 25; } void CGameClient::CClientData::KZReset() { m_CustomClient = 0; - m_SentCustomClient = false; } // function originally from Kaizo Network by +KZ, credit if used -int CGameClient::ReplaceCountryFlagWithCustomClientId(int Country) +int CGameClient::InsertCustomClientIdIntoSkinColor(int Color) { - if(!g_Config.m_ClSendClientType) - return Country; + if(!g_Config.m_ClSendClientType) + { + return Color; + } - if(m_SendingCustomClientTicks <= 1) //dont send custom flag - return Country; + union + { + int c = 0; + unsigned char b[4]; + } a; - //if some random day amount of flags conflicts with invalid flag, just send normal country - if(m_CountryFlags.Num() >= MINIMUM_CUSTOM_CLIENT_ID) - { - return Country; - } + a.c = Color; + + //printf("color %d %d %d %d\n", a.b[0], a.b[1], a.b[2], a.b[3]); + + //alpha is unused + a.b[3] = (unsigned char)CCID_COLOR_BODY_PDUCKCLIENT; + Color = a.c; - return CUSTOM_CLIENT_ID_PDUCKCLIENT; + return Color; } // function originally from Kaizo Network by +KZ, credit if used diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 6cbb88a05ca..96df252d38d 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -552,8 +552,7 @@ class CGameClient : public IGameClient // 0.7 Skin CSixup m_aSixup[NUM_DUMMIES]; - int m_CustomClient = '\0'; - bool m_SentCustomClient = false; + int m_CustomClient = 0; void KZReset(); }; @@ -1013,9 +1012,8 @@ class CGameClient : public IGameClient public: void OnKZReset(); - int ReplaceCountryFlagWithCustomClientId(int Country); + int InsertCustomClientIdIntoSkinColor(int Color); bool IsCustomClientId(int Country); - int m_SendingCustomClientTicks = -1; int HandleClientCountry(int Country, int ClientId); int GetPredictedDummyId() { return m_PredictedDummyId; } }; From aa5fab1f4b215436796fb640a74584fb6d6f5b86 Mon Sep 17 00:00:00 2001 From: +KZ <60852359+M0REKZ@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:21:16 -0300 Subject: [PATCH 5/7] Add missing license for duckicon --- data/clienticons/license.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/clienticons/license.txt b/data/clienticons/license.txt index 7f708b28846..c155e79c806 100644 --- a/data/clienticons/license.txt +++ b/data/clienticons/license.txt @@ -1,3 +1,5 @@ Licenses for the files inside this folder: kaizoicon.png by +KZ, released under CC BY-SA 4.0 + +duckicon.png by Pointer (license: CC BY 4.0) From 818907c0758ce7447077f9d152113354bb4a1e4d Mon Sep 17 00:00:00 2001 From: +KZ <60852359+M0REKZ@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:22:56 -0300 Subject: [PATCH 6/7] This is not tclient xd --- datasrc/content.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datasrc/content.py b/datasrc/content.py index af3c5e58774..537cf9425de 100644 --- a/datasrc/content.py +++ b/datasrc/content.py @@ -492,9 +492,9 @@ def FileList(fmt, num): container.sprites.Add(Sprite("part_pulley", set_extras, 4,0,1,1)) container.sprites.Add(Sprite("part_hectagon", set_extras, 6,0,2,2)) -# TClient Client Icons +# DuckClient Client Icons -# Kaizo Network +# Kaizo Client kz_image_kaizoicon= Image("kz_kaizoicon", "clienticons/kaizoicon.png") container.images.Add(kz_image_kaizoicon) set_kz_kaizoicon = SpriteSet("kz_kaizoicon", kz_image_kaizoicon, 1, 1) From 0eaa791db9d2f360fe65ef574d72ede42d0ae668 Mon Sep 17 00:00:00 2001 From: +KZ <60852359+M0REKZ@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:30:47 -0300 Subject: [PATCH 7/7] fix disconnecting players --- src/game/client/gameclient.cpp | 8 ++++++++ src/game/client/gameclient.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index ad08b0076c1..28d7102f306 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -1731,6 +1731,7 @@ void CGameClient::OnNewSnapshot() for(auto &Client : m_aClients) { Client.m_SpecCharPresent = false; + Client.m_ReceivedDDNetPlayerInfoInLastSnapshot = false; } // go through all the items in the snapshot and gather the info we want @@ -1829,6 +1830,8 @@ void CGameClient::OnNewSnapshot() } else if(m_aStats[pInfo->m_ClientId].IsActive()) m_aStats[pInfo->m_ClientId].JoinSpec(Client()->GameTick(g_Config.m_ClDummy)); + + m_aClients[pInfo->m_ClientId].m_ReceivedDDNetPlayerInfoInLastSnapshot = true; } } else if(Item.m_Type == NETOBJTYPE_DDNETPLAYER) @@ -2110,6 +2113,11 @@ void CGameClient::OnNewSnapshot() for(CClientData &Client : m_aClients) { Client.UpdateSkinInfo(); + + if(!Client.m_ReceivedDDNetPlayerInfoInLastSnapshot) + { + Client.m_CustomClient = 0; + } } // setup local pointers diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 96df252d38d..74f866b1ad8 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -553,6 +553,7 @@ class CGameClient : public IGameClient CSixup m_aSixup[NUM_DUMMIES]; int m_CustomClient = 0; + bool m_ReceivedDDNetPlayerInfoInLastSnapshot = false; void KZReset(); };