diff --git a/README.md b/README.md
index d583bc5..95a5d8a 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,7 @@ Bugfixed version of rehlds contains an additional cvars:
sv_rehlds_movecmdrate_max_burst // Max burst level of 'move' cmds for ban. Default: 2500
sv_rehlds_stringcmdrate_max_avg // Max average level of 'string' cmds for ban. Default: 80
sv_rehlds_stringcmdrate_max_burst // Max burst level of 'string' cmds for ban. Default: 400
+sv_rehlds_userinfo_transmitted_fields // Userinfo fields only with these keys will be transmitted to clients via network. If not set then all fields will be transmitted (except prefixed with underscore). Each key must be prefixed by backslash, for example "\name\model\*sid\*hltv\bottomcolor\topcolor". Default: ""
## Build instructions
diff --git a/rehlds/engine/info.cpp b/rehlds/engine/info.cpp
index d9a9fe9..c433ba4 100644
--- a/rehlds/engine/info.cpp
+++ b/rehlds/engine/info.cpp
@@ -618,3 +618,51 @@ qboolean Info_IsValid(const char *s)
return FALSE;
}
+
+#ifdef REHLDS_FIXES
+void Info_CollectFields(char *destInfo, const char *srcInfo, const char *collectedKeysOfFields)
+{
+ char keys[MAX_INFO_STRING];
+ Q_strcpy(keys, collectedKeysOfFields);
+
+ size_t userInfoLength = 0;
+ for (const char *key = strtok(keys, "\\"); key; key = strtok(nullptr, "\\"))
+ {
+ const char *value = Info_ValueForKey(srcInfo, key);
+
+ if (value[0] == '\0')
+ continue;
+
+ // Integer fields
+ if (!Q_strcmp(key, "*hltv")
+ || !Q_strcmp(key, "bottomcolor")
+ || !Q_strcmp(key, "topcolor"))
+ {
+ int intValue = Q_atoi(value);
+
+ if (!intValue)
+ continue;
+
+ destInfo[userInfoLength++] = '\\';
+ Q_strcpy(&destInfo[userInfoLength], key);
+ userInfoLength += Q_strlen(key);
+
+ destInfo[userInfoLength++] = '\\';
+ userInfoLength += Q_sprintf(&destInfo[userInfoLength], "%d", intValue);
+ }
+ // String fields
+ else
+ {
+ destInfo[userInfoLength++] = '\\';
+ Q_strcpy(&destInfo[userInfoLength], key);
+ userInfoLength += Q_strlen(key);
+
+ destInfo[userInfoLength++] = '\\';
+ Q_strcpy(&destInfo[userInfoLength], value);
+ userInfoLength += Q_strlen(value);
+ }
+
+ }
+ destInfo[userInfoLength] = '\0';
+}
+#endif
\ No newline at end of file
diff --git a/rehlds/engine/info.h b/rehlds/engine/info.h
index 364aafa..e2d39db 100644
--- a/rehlds/engine/info.h
+++ b/rehlds/engine/info.h
@@ -57,5 +57,8 @@ void Info_SetValueForStarKey(char *s, const char *key, const char *value, int ma
void Info_SetValueForKey(char *s, const char *key, const char *value, int maxsize);
void Info_Print(const char *s);
qboolean Info_IsValid(const char *s);
+#ifdef REHLDS_FIXES
+void Info_CollectFields(char *destInfo, const char *srcInfo, const char *collectedKeysOfFields);
+#endif
#endif // INFO__H
diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h
index 6d0eb02..4c933c6 100644
--- a/rehlds/engine/server.h
+++ b/rehlds/engine/server.h
@@ -545,6 +545,7 @@ extern cvar_t sv_delayed_spray_upload;
extern cvar_t sv_rehlds_force_dlmax;
extern cvar_t sv_rehlds_hull_centering;
extern cvar_t sv_rcon_condebug;
+extern cvar_t sv_rehlds_userinfo_transmitted_fields;
#endif
extern int sv_playermodel;
diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp
index 4bd0cb2..fa3ba52 100644
--- a/rehlds/engine/sv_main.cpp
+++ b/rehlds/engine/sv_main.cpp
@@ -306,6 +306,7 @@ cvar_t sv_rehlds_force_dlmax = { "sv_rehlds_force_dlmax", "0", 0, 0.0f, nullptr
cvar_t listipcfgfile = { "listipcfgfile", "listip.cfg", 0, 0.0f, nullptr };
cvar_t sv_rehlds_hull_centering = { "sv_rehlds_hull_centering", "0", 0, 0.0f, nullptr };
cvar_t sv_rcon_condebug = { "sv_rcon_condebug", "1", 0, 1.0f, nullptr };
+cvar_t sv_rehlds_userinfo_transmitted_fields = { "sv_rehlds_userinfo_transmitted_fields", "", 0, 0.0f, nullptr };
#endif
/* ../engine/sv_main.c:113 */
@@ -3829,9 +3830,18 @@ void SV_FullClientUpdate(client_t *cl, sizebuf_t *sb)
{
char info[MAX_INFO_STRING];
- Q_strncpy(info, cl->userinfo, sizeof(info) - 1);
- info[sizeof(info) - 1] = 0;
- Info_RemovePrefixedKeys(info, '_');
+#ifdef REHLDS_FIXES
+ if (sv_rehlds_userinfo_transmitted_fields.string[0] != '\0')
+ {
+ Info_CollectFields(info, cl->userinfo, sv_rehlds_userinfo_transmitted_fields.string);
+ }
+ else
+#endif // REHLDS_FIXES
+ {
+ Q_strncpy(info, cl->userinfo, sizeof(info) - 1);
+ info[sizeof(info) - 1] = 0;
+ Info_RemovePrefixedKeys(info, '_');
+ }
g_RehldsHookchains.m_SV_WriteFullClientUpdate.callChain(SV_WriteFullClientUpdate_internal, GetRehldsApiClient(cl), info, MAX_INFO_STRING, sb, GetRehldsApiClient((sb == &g_psv.reliable_datagram) ? NULL : host_client));
}
@@ -7801,6 +7811,7 @@ void SV_Init(void)
Cvar_RegisterVariable(&sv_rehlds_force_dlmax);
Cvar_RegisterVariable(&sv_rehlds_hull_centering);
Cvar_RegisterVariable(&sv_rcon_condebug);
+ Cvar_RegisterVariable(&sv_rehlds_userinfo_transmitted_fields);
#endif
for (int i = 0; i < MAX_MODELS; i++)