initial commit of render distance controller for the webclient to compensate for lacking rasterize
This commit is contained in:
parent
4b89862452
commit
a460fbeaeb
33
fog_controller/gamedata/player-fog.games.txt
Normal file
33
fog_controller/gamedata/player-fog.games.txt
Normal file
@ -0,0 +1,33 @@
|
||||
"Games"
|
||||
{
|
||||
"cstrike"
|
||||
{
|
||||
"Signatures"
|
||||
{
|
||||
"CBasePlayer::InputSetFogController"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x55\x8B\xEC\x56\x8B\xF1\x8B\x4D\x08\x83\xC1\x08\x83\x79\x10\x02\x75\x2A\x8B\x01\xBA\x2A\x2A\x2A\x2A\x85\xC0\x0F\x45\xD0\xEB\x2A\xE8\x2A\x2A\x2A\x2A\x8B\xD0\x6A\x00"
|
||||
"linux" "@_ZN11CBasePlayer21InputSetFogControllerER11inputdata_t"
|
||||
}
|
||||
}
|
||||
|
||||
"Functions"
|
||||
{
|
||||
"CBasePlayer::InputSetFogController"
|
||||
{
|
||||
"signature" "CBasePlayer::InputSetFogController"
|
||||
"callconv" "thiscall"
|
||||
"return" "void"
|
||||
"this" "entity"
|
||||
"arguments"
|
||||
{
|
||||
"inputdata"
|
||||
{
|
||||
"type" "objectptr"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
278
fog_controller/scripting/fog_controller_client.sp
Normal file
278
fog_controller/scripting/fog_controller_client.sp
Normal file
@ -0,0 +1,278 @@
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <dhooks>
|
||||
|
||||
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);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user