diff --git a/rehlds/common/cvardef.h b/rehlds/common/cvardef.h index aea0f9e03..5d9e45ec4 100644 --- a/rehlds/common/cvardef.h +++ b/rehlds/common/cvardef.h @@ -47,4 +47,16 @@ struct cvar_listener_t const char *name; }; +typedef void (*pfnCvar_HookVariable_t) (cvar_t *pCvar); + +struct cvarhook_t +{ + pfnCvar_HookVariable_t hook; + + cvar_t *cvar; + cvarhook_t *next; +}; + +qboolean Cvar_HookVariable(const char *var_name, cvarhook_t *pHook); + #endif // CVARDEF_H diff --git a/rehlds/engine/cvar.cpp b/rehlds/engine/cvar.cpp index 9285fa254..7c7ce2b7f 100644 --- a/rehlds/engine/cvar.cpp +++ b/rehlds/engine/cvar.cpp @@ -32,7 +32,8 @@ All cvar names are case insensitive! Values not. */ -cvar_t *cvar_vars; +cvar_t *cvar_vars = NULL; +cvarhook_t *cvar_hooks = NULL; char cvar_null_string[] = ""; void Cvar_Init(void) @@ -319,8 +320,10 @@ void Cvar_DirectSet(struct cvar_s *var, const char *value) void Cvar_Set(const char *var_name, const char *value) { - cvar_t *var = Cvar_FindVar(var_name); + cvar_t *var; + cvarhook_t *pHook; + var = Cvar_FindVar(var_name); if (!var) { Con_DPrintf("%s: variable \"%s\" not found\n", __func__, var_name); @@ -328,6 +331,15 @@ void Cvar_Set(const char *var_name, const char *value) } Cvar_DirectSet(var, value); + + for (pHook = cvar_hooks; pHook; pHook = pHook->next) + { + if (pHook->cvar == var) + { + pHook->hook(var); + break; + } + } } void Cvar_SetValue(const char *var_name, float value) @@ -730,3 +742,36 @@ void Cvar_CmdInit(void) { Cmd_AddCommand("cvarlist", Cmd_CvarList_f); } + +qboolean Cvar_HookVariable(const char *var_name, cvarhook_t *pHook) +{ + cvar_t *cvar; + + if (!pHook || !pHook->hook) + return FALSE; + + if (pHook->cvar || pHook->next) + return FALSE; + + cvar = Cvar_FindVar(var_name); + if (!cvar) + return FALSE; + + cvarhook_t *pCur = cvar_hooks; + pHook->cvar = cvar; + + if (pCur) + { + while (pCur->next) + pCur = pCur->next; + + pCur->next = pHook; + } + else + { + // First in chain is null, assign pHook to it + cvar_hooks = pHook; + } + + return TRUE; +} diff --git a/rehlds/engine/host.cpp b/rehlds/engine/host.cpp index 3416efdf7..31560b71f 100644 --- a/rehlds/engine/host.cpp +++ b/rehlds/engine/host.cpp @@ -57,7 +57,11 @@ cvar_t deathmatch = { "deathmatch", "0", FCVAR_SERVER, 0.0f, NULL }; cvar_t coop = { "coop", "0", FCVAR_SERVER, 0.0f, NULL }; cvar_t sys_ticrate = { "sys_ticrate", "100.0", 0, 0.0f, NULL }; + +void sys_timescale_hook_callback(cvar_t *cvar); +cvarhook_t sys_timescale_hook = { sys_timescale_hook_callback, NULL, NULL }; cvar_t sys_timescale = { "sys_timescale", "1.0", 0, 0.0f, NULL }; + cvar_t fps_max = { "fps_max", "100.0", FCVAR_ARCHIVE, 0.0f, NULL }; cvar_t host_killtime = { "host_killtime", "0.0", 0, 0.0f, NULL }; cvar_t sv_stats = { "sv_stats", "1", 0, 0.0f, NULL }; @@ -143,6 +147,9 @@ void Host_InitLocal(void) Host_InitCommands(); Cvar_RegisterVariable(&host_killtime); Cvar_RegisterVariable(&sys_ticrate); + Cvar_RegisterVariable(&sys_timescale); + Cvar_HookVariable(sys_timescale.name, &sys_timescale_hook); + Cvar_RegisterVariable(&fps_max); Cvar_RegisterVariable(&fps_override); Cvar_RegisterVariable(&host_name); @@ -355,7 +362,7 @@ void SV_ClientPrintf(const char *fmt, ...) { va_list va; char string[1024]; - + va_start(va, fmt); Q_vsnprintf(string, ARRAYSIZE(string) - 1, fmt, va); va_end(va); @@ -367,7 +374,7 @@ void SV_ClientPrintf(const char *fmt, ...) void EXT_FUNC SV_ClientPrintf_internal(const char *Dest) { char string[1024]; - + Q_strlcpy(string, Dest, min(strlen(Dest) + 1, sizeof(string))); MSG_WriteByte(&host_client->netchan.message, svc_print); MSG_WriteString(&host_client->netchan.message, string); @@ -1275,3 +1282,23 @@ void Host_Shutdown(void) g_psv.time = 0.0f; g_pcl.time = 0.0f; } + +void sys_timescale_hook_callback(cvar_t *cvar) +{ + int i; + client_t *client = NULL; + + if (!Host_IsServerActive()) + return; + + for (i = 0; i < g_psvs.maxclients; i++) + { + client = &g_psvs.clients[i]; + + if (!client->fakeclient && (client->active || client->spawned || client->connected)) + { + MSG_WriteByte(&client->netchan.message, svc_timescale); + MSG_WriteFloat(&client->netchan.message, max(0.1f, sys_timescale.value)); + } + } +} diff --git a/rehlds/engine/net_ws.cpp b/rehlds/engine/net_ws.cpp index 219b73a07..4880da9b7 100644 --- a/rehlds/engine/net_ws.cpp +++ b/rehlds/engine/net_ws.cpp @@ -651,7 +651,7 @@ void NET_AdjustLag() } lasttime = realtime; - if (allow_cheats || fakelag.value == 0.0) + if (sv_cheats.value || fakelag.value == 0.0) { if (fakelag.value != gFakeLag) { @@ -689,7 +689,7 @@ qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_ { if (fakeloss.value != 0.0) { - if (allow_cheats) + if (sv_cheats.value) { static int losscount[NS_MAX] = {}; ++losscount[sock]; diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h index 4bdd7efb6..eedb6f076 100644 --- a/rehlds/engine/server.h +++ b/rehlds/engine/server.h @@ -349,7 +349,6 @@ extern cvar_t sv_proxies; extern cvar_t sv_outofdatetime; extern cvar_t mapchangecfgfile; -extern qboolean allow_cheats; extern cvar_t mp_logecho; extern cvar_t mp_logfile; extern cvar_t sv_allow_download; diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index fa79fe9c5..b3779c959 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -100,7 +100,6 @@ redirect_t sv_redirected; netadr_t sv_redirectto; GameType_e g_eGameType = GT_Unitialized; -qboolean allow_cheats; char *gNullString = ""; int SV_UPDATE_BACKUP = SINGLEPLAYER_BACKUP; @@ -130,6 +129,12 @@ cvar_t sv_waterfriction = { "sv_waterfriction", "1", FCVAR_SERVER, 0.0f, NULL }; cvar_t sv_zmax = { "sv_zmax", "4096", FCVAR_SPONLY, 0.0f, NULL }; cvar_t sv_wateramp = { "sv_wateramp", "0", 0, 0.0f, NULL }; +void sv_cheats_hook_callback(cvar_t *cvar); +void mapcyclefile_hook_callback(cvar_t *cvar); + +cvarhook_t sv_cheats_hook = { sv_cheats_hook_callback, NULL, NULL }; +cvarhook_t mapcyclefile_hook = { mapcyclefile_hook_callback, NULL, NULL }; + cvar_t sv_skyname = { "sv_skyname", "desert", 0, 0.0f, NULL }; cvar_t mapcyclefile = { "mapcyclefile", "mapcycle.txt", 0, 0.0f, NULL }; cvar_t motdfile = { "motdfile", "motd.txt", 0, 0.0f, NULL }; @@ -1173,7 +1178,7 @@ void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client) MSG_WriteByte(msg, svc_sendextrainfo); MSG_WriteString(msg, com_clientfallback); - MSG_WriteByte(msg, allow_cheats); + MSG_WriteByte(msg, sv_cheats.value != 0); SV_WriteDeltaDescriptionsToClient(msg); SV_SetMoveVars(); @@ -6257,7 +6262,6 @@ int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot) gGlobalVariables.serverflags = g_psvs.serverflags; gGlobalVariables.mapname = (size_t)g_psv.name - (size_t)pr_strings; gGlobalVariables.startspot = (size_t)g_psv.startspot - (size_t)pr_strings; - allow_cheats = sv_cheats.value; SV_SetMoveVars(); return 1; @@ -6576,6 +6580,42 @@ void EXT_FUNC SV_SerializeSteamid(USERID_t* id, USERID_t* serialized) *serialized = *id; } +void sv_cheats_hook_callback(cvar_t *cvar) +{ + int i; + client_t *client = NULL; + + if (!Host_IsServerActive()) + return; + + for (i = 0; i < g_psvs.maxclients; i++) + { + client = &g_psvs.clients[i]; + + if (!client->fakeclient && (client->active || client->spawned || client->connected)) + { + MSG_WriteByte(&client->netchan.message, svc_sendextrainfo); + MSG_WriteString(&client->netchan.message, ""); + MSG_WriteByte(&client->netchan.message, sv_cheats.value != 0); + } + } +} + +void mapcyclefile_hook_callback(cvar_t *cvar) +{ + char buf[MAX_PATH + 4]; + + if (!Q_strcmp(COM_FileExtension(cvar->string), "txt")) + return; + + Q_snprintf(buf, sizeof(buf) - 3, "%s.txt", cvar->string); + + if (!Q_strcmp(COM_FileExtension(buf), "txt")) + Cvar_DirectSet(cvar, buf); + else + Cvar_DirectSet(cvar, "mapcycle.txt"); +} + void SV_BanId_f(void) { char szreason[256]; @@ -8014,6 +8054,7 @@ void SV_Init(void) Cvar_RegisterVariable(&sv_skyname); Cvar_RegisterVariable(&sv_maxvelocity); Cvar_RegisterVariable(&sv_cheats); + Cvar_HookVariable(sv_cheats.name, &sv_cheats_hook); if (COM_CheckParm("-dev")) Cvar_SetValue("sv_cheats", 1.0); Cvar_RegisterVariable(&sv_spectatormaxspeed); @@ -8025,6 +8066,7 @@ void SV_Init(void) Cvar_RegisterVariable(&sv_logbans); Cvar_RegisterVariable(&hpk_maxsize); Cvar_RegisterVariable(&mapcyclefile); + Cvar_HookVariable(mapcyclefile.name, &mapcyclefile_hook); Cvar_RegisterVariable(&motdfile); Cvar_RegisterVariable(&servercfgfile); Cvar_RegisterVariable(&mapchangecfgfile); diff --git a/rehlds/engine/zone.cpp b/rehlds/engine/zone.cpp index afd84697a..3a1ab65f7 100644 --- a/rehlds/engine/zone.cpp +++ b/rehlds/engine/zone.cpp @@ -679,7 +679,7 @@ void Cache_Force_Flush() void Cache_Flush() { - if (g_pcl.maxclients <= 1 || allow_cheats) + if (g_pcl.maxclients <= 1 || sv_cheats.value) { Cache_Force_Flush(); } diff --git a/rehlds/msvc/ReHLDS.vcxproj b/rehlds/msvc/ReHLDS.vcxproj index 2078e8301..dc153551e 100644 --- a/rehlds/msvc/ReHLDS.vcxproj +++ b/rehlds/msvc/ReHLDS.vcxproj @@ -463,6 +463,7 @@ {6973dca5-253c-4d84-b51e-187e035eae06} + false diff --git a/rehlds/rehlds/rehlds_api_impl.cpp b/rehlds/rehlds/rehlds_api_impl.cpp index d18622036..8d7f9dad6 100644 --- a/rehlds/rehlds/rehlds_api_impl.cpp +++ b/rehlds/rehlds/rehlds_api_impl.cpp @@ -52,7 +52,9 @@ char* EXT_FUNC GetClientFallback_api() { } int* EXT_FUNC GetAllowCheats_api() { - return &allow_cheats; + static int sv_cheats_stub = 0; + Con_Printf("WARNING! allow_cheats marked as deprecated! Use sv_cheats cvar directly!\n"); + return &sv_cheats_stub; } bool EXT_FUNC GSBSecure_api() {