diff --git a/LagCompensation/scripting/LagCompensation_nide_edit.sp b/LagCompensation/scripting/LagCompensation_nide_edit.sp index 1dc1b3d..c93de20 100644 --- a/LagCompensation/scripting/LagCompensation_nide_edit.sp +++ b/LagCompensation/scripting/LagCompensation_nide_edit.sp @@ -18,7 +18,7 @@ public Plugin myinfo = name = "LagCompensation", author = "BotoX, Vauff, .Rushaway, maxime1907", description = "", - version = "1.1.0", + version = "1.2.0", url = "" }; @@ -112,6 +112,12 @@ EntityLagData g_aEntityLagData[MAX_ENTITIES]; int g_iNumEntities = 0; bool g_bCleaningUp = true; +// When more than sm_lagcomp_max_entities entities are lag compensation at the same time we switch off lag compensation +//enabled again on next round or through command +bool g_bLagCompSuspended = false; // nothing new gets compensated +bool g_bReleasePending = false; // the tracked entities still have to be released +int g_iMaxEntities = MAX_ENTITIES; + // Cache int g_iGameTick; float g_fTickInterval; @@ -169,6 +175,7 @@ int g_iDisableLagComp[MAXPLAYERS + 1]; ConVar g_cvCompenseEntityClass; ConVar g_cvCheckUserPing; ConVar g_cvMinimumPing; +ConVar g_cvMaxEntities; public void OnPluginStart() { @@ -177,6 +184,7 @@ public void OnPluginStart() g_cvCompenseEntityClass = CreateConVar("sm_lagcomp_entityclass", "0", "Only lagcompensate: [0 = All | 1 = func_physbox only]", _, true, 0.0, true, 1.0); g_cvCheckUserPing = CreateConVar("sm_lagcomp_checkuserping", "0", "Check user's ping before lagcompensating them [0 = Disabled | 1 = Enabled]", _, true, 0.0, true, 1.0); g_cvMinimumPing = CreateConVar("sm_lagcomp_ping", "180", "Minimum ping threshold to apply lagcomp on a client", _, true, 0.0); + g_cvMaxEntities = CreateConVar("sm_lagcomp_max_entities", "30", "Maximum entities lag compensated at the same time. Going over it disables lag compensation for everyone until the next round. [1-256]", _, true, 1.0, true, float(MAX_ENTITIES)); AutoExecConfig(true); @@ -347,6 +355,7 @@ public void OnPluginStart() HookConVarChange(g_cvCompenseEntityClass, OnConVarChanged); HookConVarChange(g_cvCheckUserPing, OnConVarChanged); HookConVarChange(g_cvMinimumPing, OnConVarChanged); + HookConVarChange(g_cvMaxEntities, OnConVarChanged); g_hCookie_LagCompSettings = RegClientCookie("lagcomp_settings", "LagCompensation Settings", CookieAccess_Private); @@ -360,6 +369,7 @@ public void OnPluginStart() RegAdminCmd("sm_unlag", Command_AddLagCompensation, ADMFLAG_ROOT, "sm_unlag [late]"); RegAdminCmd("sm_lagged", Command_CheckLagCompensated, ADMFLAG_ROOT, "sm_lagged"); + RegAdminCmd("sm_lagcomp_enable", Command_EnableLagCompensation, ADMFLAG_GENERIC, "Re-enables lag compensation after it was disabled for going over sm_lagcomp_max_entities"); FilterClientSolidTouch(g_aaFilterClientSolidTouch, true); BlockTriggerMoved(g_aBlockTriggerMoved, true); @@ -407,6 +417,7 @@ public void OnConfigsExecuted() g_iCompenseEntityClass = GetConVarInt(g_cvCompenseEntityClass); g_bCheckPing = GetConVarBool(g_cvCheckUserPing); g_iMinPing = GetConVarInt(g_cvMinimumPing); + g_iMaxEntities = GetConVarInt(g_cvMaxEntities); } void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue) @@ -417,6 +428,8 @@ void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue g_bCheckPing = GetConVarBool(convar); else if (convar == g_cvMinimumPing) g_iMinPing = GetConVarInt(convar); + else if (convar == g_cvMaxEntities) + g_iMaxEntities = GetConVarInt(convar); } public void OnMapStart() @@ -644,6 +657,10 @@ bool CheckEntityForLagComp(int entity, const char[] classname, bool bRecursive=f if(!IsValidEntity(entity)) return false; + // Disabled for the rest of the round. + if(g_bLagCompSuspended) + return false; + if(g_aLagCompensated[entity] != -1) return false; @@ -710,6 +727,13 @@ bool CheckEntityForLagComp(int entity, const char[] classname, bool bRecursive=f if(!bGoodParents) return false; + // One more than allowed: switch lag compensation off until the next round. + if(g_iNumEntities >= g_iMaxEntities) + { + SuspendLagCompensation(); + return false; + } + if(AddEntityForLagCompensation(entity, bTrigger)) { if(bTrigger) @@ -800,9 +824,32 @@ public MRESReturn Detour_OnRestartRound() { g_bCleaningUp = true; + ReleaseAllEntities(); + + for(int i = 0; i < sizeof(g_aBlacklisted); i++) + g_aBlacklisted[i] = 0; + + // New round, lag compensation is back on. + g_bLagCompSuspended = false; + + g_bCleaningUp = false; + return MRES_Ignored; +} + +// Stops compensating everything that is currently tracked. +void ReleaseAllEntities() +{ + g_bReleasePending = false; + for(int i = 0; i < g_iNumEntities; i++) { int iEntity = g_aEntityLagData[i].iEntity; + bool bValid = IsValidEntity(iEntity); + + // Should never be rewound at this point, but never leave an entity in the past. + if(g_aEntityLagData[i].bRestore && bValid) + RestoreEntityFromRecord(iEntity, g_aaLagRecords[i][g_aEntityLagData[i].iRecordIndex]); + g_aEntityLagData[i].bRestore = false; g_aLagCompensated[iEntity] = -1; ClearBit(g_aBlockTriggerTouchPlayers, iEntity); @@ -813,22 +860,39 @@ public MRESReturn Detour_OnRestartRound() ClearBit(g_aaFilterClientSolidTouch, client * MAX_EDICTS + iEntity); } - if(g_aEntityLagData[i].iDeleted) + if(g_aEntityLagData[i].iDeleted && bValid) { - if(IsValidEntity(iEntity)) - RemoveEdict(iEntity); + ClearBit(g_aBlacklisted, iEntity); + RemoveEdict(iEntity); } g_aEntityLagData[i].iEntity = INVALID_ENT_REFERENCE; } - for(int i = 0; i < sizeof(g_aBlacklisted); i++) - g_aBlacklisted[i] = 0; - g_iNumEntities = 0; +} - g_bCleaningUp = false; - return MRES_Ignored; +void ReleaseAllEntitiesNow() +{ + bool bWasCleaningUp = g_bCleaningUp; + g_bCleaningUp = true; + ReleaseAllEntities(); + g_bCleaningUp = bWasCleaningUp; +} + +void SuspendLagCompensation() +{ + if(g_bLagCompSuspended) + return; + + g_bLagCompSuspended = true; + g_bReleasePending = true; + + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && !IsFakeClient(client) && !g_bDisableLagComp[client]) + CPrintToChat(client, "%s LagCompensation has been {red}disabled{default} until the next round, too many entities needed to be compensated.", PREFIX); + } } // https://developer.valvesoftware.com/wiki/Logic_measure_movement @@ -895,6 +959,9 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 if(!IsClientInGame(client) || !IsPlayerAlive(client) || IsFakeClient(client)) return Plugin_Continue; + if(g_bLagCompSuspended) + return Plugin_Continue; + int iTargetTick = tickcount - g_aLerpTicks[client]; // -1 because the newest record in the list is one tick old @@ -980,6 +1047,13 @@ public void OnPostPlayerThinkFunctions() public MRESReturn Hook_EndGameFrame() { + // Lag compensation got disabled this frame, let go of everything. + if(g_bReleasePending) + { + ReleaseAllEntitiesNow(); + return MRES_Ignored; + } + for(int i = 0; i < g_iNumEntities; i++) { if(g_aEntityLagData[i].iDeleted) @@ -1355,11 +1429,43 @@ public Action Command_AddLagCompensation(int client, int argc) late = view_as(StringToInt(sArgs)); } + if(g_bLagCompSuspended) + { + ReplyToCommand(client, "[SM] LagCompensation is disabled until the next round, use sm_lagcomp_enable first."); + return Plugin_Handled; + } + AddEntityForLagCompensation(entity, late); return Plugin_Handled; } +public Action Command_EnableLagCompensation(int client, int argc) +{ + if(!g_bLagCompSuspended) + { + ReplyToCommand(client, "[SM] LagCompensation is already enabled."); + return Plugin_Handled; + } + + // Let go of whatever was tracked before it got disabled, so only + // entities that spawn from now on are compensated. + if(g_bReleasePending) + ReleaseAllEntitiesNow(); + + g_bLagCompSuspended = false; + + ReplyToCommand(client, "[SM] LagCompensation has been re-enabled."); + + for(int i = 1; i <= MaxClients; i++) + { + if(IsClientInGame(i) && !IsFakeClient(i) && !g_bDisableLagComp[i]) + CPrintToChat(i, "%s LagCompensation has been {green}re-enabled{default} by an admin.", PREFIX); + } + + return Plugin_Handled; +} + public Action Command_CheckLagCompensated(int client, int argc) { if(argc == 0) @@ -1377,6 +1483,9 @@ public Action Command_CheckLagCompensated(int client, int argc) PrintToConsole(client, "%2d. #%d %s \"%s\" (#%d)", i, g_aEntityLagData[i].iEntity, sClassname, sTargetname, iHammerID); } + PrintToConsole(client, "Active: %d / %d%s", g_iNumEntities, g_iMaxEntities, + g_bLagCompSuspended ? " | DISABLED until next round (over the limit)" : ""); + return Plugin_Handled; } @@ -1505,6 +1614,9 @@ public void ToggleLagCompSettings(int client) SaveLagCompSettings(client); CPrintToChat(client, "%s LagCompensation has been %s.", PREFIX, g_bDisableLagComp[client] ? "disabled" : "enabled"); + + if(!g_bDisableLagComp[client] && g_bLagCompSuspended) + CPrintToChat(client, "%s It is currently {red}disabled{default} for everyone until the next round (too many entities).", PREFIX); } public void ToggleLagCompLasers(int client) @@ -1561,6 +1673,11 @@ public Action CheckLagComp(int client, int args) CReplyToCommand(client, "%s LagCompensation is %s for {olive}%N", PREFIX, g_bDisableLagComp[target] ? "disabled" : sEnable, target); CReplyToCommand(client, "%s Laser compensation: %s", PREFIX, g_bPlayerLaserCompensated[target] ? "enabled" : "disabled"); + if(g_bLagCompSuspended) + CReplyToCommand(client, "%s Server status: {red}disabled{default} for everyone until the next round (more than %d entities needed to be compensated).", PREFIX, g_iMaxEntities); + else + CReplyToCommand(client, "%s Server status: {green}active{default}.", PREFIX); + // g_iDisableLagComp also ramps from the ping threshold, so report it when they haven't opted out. if(!g_bDisableLagComp[target] && g_iDisableLagComp[target] > 0) CReplyToCommand(client, "%s Currently reduced: %d of %d ticks skipped%s.", PREFIX, @@ -1573,7 +1690,10 @@ public Action CheckLagComp(int client, int args) public void ShowSettingsMenu(int client) { Menu menu = new Menu(MenuHandler_MainMenu); - menu.SetTitle("LagCompensation Settings"); + if(g_bLagCompSuspended) + menu.SetTitle("LagCompensation Settings\nCurrently disabled until the next round (too many entities)"); + else + menu.SetTitle("LagCompensation Settings"); menu.ExitBackButton = true; char buffer[128], buffer_lasers[128], msg_buffer[128];