#include #include #include public Plugin myinfo = { name = "Render Distance Limiter", author = "Dysphie, repurposed for unloze webclient using some AI", description = "", version = "", url = "" }; int g_iClientFogEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... }; float g_OverrideDist[MAXPLAYERS + 1] = { -1.0, ... }; bool bEnabled[MAXPLAYERS + 1]; float g_fClientEstimatedFPS[MAXPLAYERS + 1]; // New tracking arrays for your global variables section float g_fLastStableDist[MAXPLAYERS + 1] = { -1.0, ... }; float g_fDistCooldown[MAXPLAYERS + 1] = { 0.0, ... }; int g_iLastCmdNum[MAXPLAYERS + 1]; float g_fFPSIntervalStart[MAXPLAYERS + 1]; int g_iCmdsInInterval[MAXPLAYERS + 1]; public void OnPluginStart() { SetupDetours(); CreateTimer(0.5, Timer_printFPS, _, TIMER_REPEAT); } //ai generated public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) { if (IsFakeClient(client) || !bEnabled[client]) return Plugin_Continue; // Check if this is a brand new user command execution frame if (cmdnum != g_iLastCmdNum[client]) { g_iLastCmdNum[client] = cmdnum; g_iCmdsInInterval[client]++; } float fCurrentTime = GetEngineTime(); float fTimeElapsed = fCurrentTime - g_fFPSIntervalStart[client]; // Evaluate the true input frequency every 0.5 seconds if (fTimeElapsed >= 0.5) { if (g_fFPSIntervalStart[client] > 0.0) { // Raw calculated input framerate based on sequential command progression float fCalculatedFPS = float(g_iCmdsInInterval[client]) / fTimeElapsed; // FAST-DROP BYPASS: If the client just lost more than 25% of their frame rate instantly // skip the dampening math and force the estimation down immediately. if (fCalculatedFPS < (g_fClientEstimatedFPS[client] * 0.75)) { g_fClientEstimatedFPS[client] = fCalculatedFPS; // Hard-drop the value } else { // Smoothly recover/climb when frame rates are stable or increasing g_fClientEstimatedFPS[client] = (g_fClientEstimatedFPS[client] * 0.8) + (fCalculatedFPS * 0.2); } } // Reset interval buckets g_fFPSIntervalStart[client] = fCurrentTime; g_iCmdsInInterval[client] = 0; } return Plugin_Continue; } //ai generated public Action Timer_printFPS(Handle timer) { for (int i = 1; i <= MaxClients; i++) { if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && bEnabled[i]) { float fCurrentFPS = g_fClientEstimatedFPS[i] - 4.0; float currentDist = g_OverrideDist[i]; float targetDist = currentDist; // 1. HARD CRASH: FPS has tanked down to unplayable levels. if (fCurrentFPS <= 25.0) { // If we have a cached, proven stable distance, use it immediately! if (g_fLastStableDist[i] != -1.0 && g_fLastStableDist[i] < currentDist) { targetDist = g_fLastStableDist[i]; } else { // Emergency fallback steps if we dont have a cached history yet if (currentDist == -1.0 || currentDist > 1200.0) { targetDist = 1200.0; } else { targetDist = 600.0; } } // Penalize the cooldown heavily because we just choked on rendering g_fDistCooldown[i] = GetEngineTime() + 15.0; } // 2. WARNING ZONE: Framerate is beginning to dip else if (fCurrentFPS <= 38.0) { if (currentDist == -1.0 || currentDist > 2000.0) { targetDist = 2000.0; g_fDistCooldown[i] = GetEngineTime() + 10.0; } } // 3. RECOVERY ZONE: Performance is solid. Lets see if we can open up the view. else if (fCurrentFPS >= 48.0) { if (currentDist != -1.0) { // Since the game is running flawlessly at this specific distance, // we update our safety cache to remember this specific float. g_fLastStableDist[i] = currentDist; // Only venture out if our time barrier has expired if (GetEngineTime() >= g_fDistCooldown[i]) { if (currentDist == 600.0) targetDist = 1200.0; else if (currentDist == 1200.0) targetDist = 2000.0; else if (currentDist == 2000.0) targetDist = 4000.0; else if (currentDist == 4000.0) targetDist = -1.0; // Give the client a test window to sample the new distance g_fDistCooldown[i] = GetEngineTime() + 8.0; } } else { // If the client is running fine at infinite distance (-1.0), // clear the history out so we can recalculate from a clean slate later g_fLastStableDist[i] = -1.0; } } if (targetDist != currentDist) { ApplyFogValues(i, targetDist); } } } return Plugin_Continue; } void ApplyFogValues(int client, float dist) { g_OverrideDist[client] = dist; int fog = EntRefToEntIndex(g_iClientFogEntity[client]); // Create the persistent entity once if it vanished or hasnt been created yet if (fog == -1 || !IsValidEntity(fog)) { fog = CreateEntityByName("env_fog_controller"); if (fog != -1) { DispatchSpawn(fog); g_iClientFogEntity[client] = EntIndexToEntRef(fog); } } if (fog != -1 && IsValidEntity(fog)) { if (dist == -1.0) { // Back to map defaults safely SetEntProp(fog, Prop_Send, "m_fog.enable", 0); SetEntPropFloat(fog, Prop_Send, "m_fog.farz", 0.0); } else { // Apply strict culling boundaries explicitly SetEntProp(fog, Prop_Send, "m_fog.enable", 1); SetEntPropFloat(fog, Prop_Send, "m_fog.farz", dist); SetEntPropFloat(fog, Prop_Send, "m_fog.end", dist); SetEntPropFloat(fog, Prop_Send, "m_fog.maxdensity", 1.0); } // Keep the entity assigned cleanly inside data tables SetFogController(client, fog); // Single fire state changes to replicate out smoothly ChangeEdictState(client, FindSendPropInfo("CBasePlayer", "m_hCtrl")); } } public void OnClientDisconnect(int client) { // Clean up entity allocation to prevent lingering map errors int fog = EntRefToEntIndex(g_iClientFogEntity[client]); if (fog != -1 && IsValidEntity(fog)) { RemoveEntity(fog); } g_iClientFogEntity[client] = INVALID_ENT_REFERENCE; g_OverrideDist[client] = -1.0; bEnabled[client] = false; } void SetupDetours() { GameData gamedata = new GameData("player-fog.games"); if (!gamedata) { SetFailState("Missing gamedata file"); } DynamicDetour detour = DynamicDetour.FromConf(gamedata, "CBasePlayer::InputSetFogController"); if (!detour) SetFailState("Failed to find signature CBasePlayer::InputSetFogController"); detour.Enable(Hook_Pre, Detour_InputSetFogController); delete detour; } MRESReturn Detour_InputSetFogController(int client, DHookParam params) { RequestFrame(Frame_FogControllerChanged, GetClientSerial(client)); return MRES_Ignored; } void FogControllerChanged(int client) { if (g_OverrideDist[client] != -1.0) { ApplyFogValues(client, g_OverrideDist[client]); } } void Frame_FogControllerChanged(int clientSerial) { int client = GetClientFromSerial(clientSerial); if (client && IsClientInGame(client)) { FogControllerChanged(client); } } public void OnClientAuthorized(int client, const char[] auth) { bEnabled[client] = false; g_OverrideDist[client] = -1.0; g_iClientFogEntity[client] = INVALID_ENT_REFERENCE; char sIP[32]; GetClientIP(client, sIP, sizeof(sIP)); char allowed_ips[128]; ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips"); if (sv_set_steam_id_ips != null) { sv_set_steam_id_ips.GetString(allowed_ips, sizeof(allowed_ips)); if (StrEqual(sIP, allowed_ips)) { bEnabled[client] = true; } } } void SetFogController(int client, int fog) { SetEntPropEnt(client, Prop_Data, "m_hCtrl", fog); }