diff --git a/AntiLagSwitch/scripting/AntiLagSwitch.sp b/AntiLagSwitch/scripting/AntiLagSwitch.sp index 04431a28..4fb799be 100644 --- a/AntiLagSwitch/scripting/AntiLagSwitch.sp +++ b/AntiLagSwitch/scripting/AntiLagSwitch.sp @@ -6,12 +6,14 @@ #pragma semicolon 1 #pragma newdecls required +#define MAX_MISSED_TICKS 16 + public Plugin myinfo = { name = "AntiLagSwitch", author = "BotoX", description = "", - version = "0.0", + version = "1.0", url = "" }; @@ -72,7 +74,7 @@ public void OnClientDisconnect(int client) public void OnPrePlayerThinkFunctions() { - int minimum = GetGameTickCount() - 32; + int minimum = GetGameTickCount() - MAX_MISSED_TICKS; for(int client = 1; client <= MaxClients; client++) { if(IsClientInGame(client) && (IsFakeClient(client) || g_LastProcessed[client] < minimum)) diff --git a/LagCompensation/gamedata/LagCompensation.games.txt b/LagCompensation/gamedata/LagCompensation.games.txt index c616d185..53306a61 100644 --- a/LagCompensation/gamedata/LagCompensation.games.txt +++ b/LagCompensation/gamedata/LagCompensation.games.txt @@ -7,7 +7,7 @@ "::UTIL_Remove" { "library" "server" - "linux" "@_Z11UTIL_RemoveP11CBaseEntity" + "linux" "@_Z11UTIL_RemoveP18IServerNetworkable" } "CCSGameRules::RestartRound" @@ -52,7 +52,119 @@ { "oldObj" { - "type" "cbaseentity" + "type" "objectptr" + } + } + } + + "CCSGameRules__RestartRound" + { + "signature" "CCSGameRules::RestartRound" + "callconv" "thiscall" + "return" "void" + "this" "ignore" + } + + "CEntityTouchManager__FrameUpdatePostEntityThink" + { + "signature" "CEntityTouchManager::FrameUpdatePostEntityThink" + "callconv" "cdecl" + "return" "void" + } + + "CLogicMeasureMovement__SetTarget" + { + "signature" "CLogicMeasureMovement::SetTarget" + "callconv" "thiscall" + "return" "void" + "this" "entity" + "arguments" + { + "pName" + { + "type" "charptr" + } + } + } + + "CLogicMeasureMovement__SetTarget_post" + { + "signature" "CLogicMeasureMovement::SetTarget" + "callconv" "thiscall" + "return" "void" + "this" "ignore" + "arguments" + { + "pName" + { + "type" "charptr" + } + } + } + } + + "Offsets" + { + "CServerNetworkableProperty::m_pOuter" + { + "linux" "8" + } + } + } + + "csgo" + { + "Signatures" + { + "::UTIL_Remove" + { + "library" "server" + "linux" "\x55\x89\xE5\x83\xEC\x48\x89\x5D\xF4\x8B\x5D\x08\x89\x75\xF8\x89\x7D\xFC\x85\xDB" + } + + "CCSGameRules::RestartRound" + { + "library" "server" + "linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\x3C\x03\x00\x00" + } + + "CLogicMeasureMovement::SetTarget" + { + "library" "server" + "linux" "\x55\x89\xE5\x56\x53\x83\xEC\x20\x8B\x5D\x0C\xC7\x44\x24\x18\x00\x00\x00\x00\x8B\x75\x08\xC7\x44\x24\x14\x00\x00\x00\x00\xC7\x44\x24\x10\x00\x00\x00\x00\xC7\x44\x24\x0C\x00\x00\x00\x00\x89\x5C\x24\x08\xC7\x44\x24\x04\x00\x00\x00\x00\xC7\x04\x24\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8B\x10\x89\x04\x24\xFF\x52\x0C\x8B\x0D\x2A\x2A\x2A\x2A\x8B\x00\x83\xF8\xFF\x89\x86\xBC\x03\x00\x00" + } + + "CEntityTouchManager::FrameUpdatePostEntityThink" + { + "library" "server" + "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x3C\xA1\x2A\x2A\x2A\x2A\x8B\x5D\x08\x85\xC0" + } + + "CalcAbsolutePosition" + { + "library" "server" + "linux" "\x55\x89\xE5\x81\xEC\x98\x00\x00\x00\x89\x5D\xF4\x8B\x5D\x08\x89\x75\xF8\x89\x7D\xFC\x8B\x83\xDC\x00\x00\x00" + } + + "MarkPartitionHandleDirty" + { + "library" "server" + "linux" "\x55\x89\xE5\x53\x83\xEC\x14\x8B\x5D\x08\x8B\x43\x04\xF6\x80\xDD\x00\x00\x00\x80" + } + } + + "Functions" + { + "UTIL_Remove" + { + "signature" "::UTIL_Remove" + "return" "void" + "callconv" "cdecl" + "arguments" + { + "oldObj" + { + "type" "objectptr" } } } @@ -83,7 +195,7 @@ { "pName" { - "type" "charptr" + "type" "charptr" } } } @@ -98,10 +210,18 @@ { "pName" { - "type" "charptr" + "type" "charptr" } } } } + + "Offsets" + { + "CServerNetworkableProperty::m_pOuter" + { + "linux" "8" + } + } } } diff --git a/LagCompensation/scripting/LagCompensation.sp b/LagCompensation/scripting/LagCompensation.sp index f544a588..edd78313 100644 --- a/LagCompensation/scripting/LagCompensation.sp +++ b/LagCompensation/scripting/LagCompensation.sp @@ -4,7 +4,8 @@ #include #include #include -#include + +#define PLUGIN_VERSION "1.0" #define SetBit(%1,%2) ((%1)[(%2) >> 5] |= (1 << ((%2) & 31))) #define ClearBit(%1,%2) ((%1)[(%2) >> 5] &= ~(1 << ((%2) & 31))) @@ -77,7 +78,6 @@ enum #define MAX_RECORDS 32 #define MAX_ENTITIES 256 -//#define DEBUG enum struct LagRecord { @@ -98,7 +98,6 @@ enum struct EntityLagData int iSpawned; int iDeleted; int iNotMoving; - int iTouchStamp; bool bRestore; bool bLateKill; LagRecord RestoreData; @@ -109,6 +108,8 @@ EntityLagData g_aEntityLagData[MAX_ENTITIES]; int g_iNumEntities = 0; bool g_bCleaningUp = true; +bool g_bHasOnEntitySpawned = false; + Handle g_hCalcAbsolutePosition; Handle g_hMarkPartitionHandleDirty; @@ -120,14 +121,16 @@ Handle g_hFrameUpdatePostEntityThink; Handle g_hActivate; Handle g_hAcceptInput; +int g_iNetworkableOuter; int g_iParent; int g_iSpawnFlags; -int g_iTouchStamp; int g_iCollision; int g_iSolidFlags; int g_iSolidType; int g_iSurroundType; int g_iEFlags; +int g_iLerpTime = -1; + int g_iVecOrigin; int g_iVecAbsOrigin; int g_iAngRotation; @@ -143,15 +146,11 @@ int g_aBlacklisted[MAX_EDICTS / 32]; Handle g_hCookie_DisableLagComp; bool g_bDisableLagComp[MAXPLAYERS+1]; -int g_iLastCommandUsed[MAXPLAYERS+1]; +int g_iDisableLagComp[MAXPLAYERS+1]; public void OnPluginStart() { - g_hCookie_DisableLagComp = RegClientCookie("disable_lagcomp", "", CookieAccess_Private); - RegConsoleCmd("sm_lagcomp", OnToggleLagCompSettings); - RegConsoleCmd("sm_ping", OnToggleLagCompSettings); - RegConsoleCmd("sm_0ping", OnToggleLagCompSettings); - SetCookieMenuItem(MenuHandler_CookieMenu, 0, "LagCompensation"); + CreateConVar("sm_lagcomp_version", PLUGIN_VERSION, "LagCompensation Version", FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD).SetString(PLUGIN_VERSION); Handle hGameData = LoadGameConfigFile("LagCompensation.games"); if(!hGameData) @@ -246,6 +245,14 @@ public void OnPluginStart() SetFailState("Failed to detour CEntityTouchManager__FrameUpdatePostEntityThink."); } + + g_iNetworkableOuter = GameConfGetOffset(hGameData, "CServerNetworkableProperty::m_pOuter"); + if(g_iNetworkableOuter == -1) + { + delete hGameData; + SetFailState("GameConfGetOffset(hGameData, \"CServerNetworkableProperty::m_pOuter\") failed!"); + } + delete hGameData; @@ -279,6 +286,14 @@ public void OnPluginStart() delete hGameData; + g_bHasOnEntitySpawned = GetFeatureStatus(FeatureType_Capability, "SDKHook_OnEntitySpawned") == FeatureStatus_Available; + + g_hCookie_DisableLagComp = RegClientCookie("disable_lagcomp", "", CookieAccess_Private); + RegConsoleCmd("sm_lagcomp", OnToggleLagCompSettings); + RegConsoleCmd("sm_0ping", OnToggleLagCompSettings); + SetCookieMenuItem(MenuHandler_CookieMenu, 0, "LagCompensation"); + + CreateTimer(0.1, DisableLagCompTimer, _, TIMER_REPEAT); RegAdminCmd("sm_unlag", Command_AddLagCompensation, ADMFLAG_RCON, "sm_unlag "); RegAdminCmd("sm_lagged", Command_CheckLagCompensated, ADMFLAG_GENERIC, "sm_lagged"); @@ -331,7 +346,6 @@ public void OnMapStart() g_iParent = FindDataMapInfo(0, "m_pParent"); g_iSpawnFlags = FindDataMapInfo(0, "m_spawnflags"); - g_iTouchStamp = FindDataMapInfo(0, "touchStamp"); g_iCollision = FindDataMapInfo(0, "m_Collision"); g_iSolidFlags = FindDataMapInfo(0, "m_usSolidFlags"); g_iSolidType = FindDataMapInfo(0, "m_nSolidType"); @@ -348,10 +362,14 @@ public void OnMapStart() /* Late Load */ if(bLate) { - for (int i = 1; i <= MaxClients; i++) + for (int client = 1; client <= MaxClients; client++) { - if (IsValidClient(i) && AreClientCookiesCached(i)) - OnClientCookiesCached(i); + if(IsClientInGame(client)) + { + OnClientPutInServer(client); + if(AreClientCookiesCached(client)) + OnClientCookiesCached(client); + } } int entity = INVALID_ENT_REFERENCE; @@ -374,6 +392,39 @@ public void OnMapStart() g_bLateLoad = false; } +public void OnMapEnd() +{ + Detour_OnRestartRound(); + g_bCleaningUp = true; +} + +public void OnClientPutInServer(int client) +{ + if(g_iLerpTime == -1) + { + g_iLerpTime = FindDataMapInfo(client, "m_fLerpTime"); + } + + g_bDisableLagComp[client] = false; + g_iDisableLagComp[client] = 0; +} + +public void OnClientCookiesCached(int client) +{ + char sBuffer[16]; + GetClientCookie(client, g_hCookie_DisableLagComp, sBuffer, sizeof(sBuffer)); + if(sBuffer[0]) + g_bDisableLagComp[client] = true; + else + g_bDisableLagComp[client] = false; +} + +public void OnClientDisconnect(int client) +{ + g_bDisableLagComp[client] = false; + g_iDisableLagComp[client] = 0; +} + public void OnEntityCreated(int entity, const char[] classname) { if(g_bCleaningUp) @@ -387,6 +438,19 @@ public void OnEntityCreated(int entity, const char[] classname) { DHookEntity(g_hAcceptInput, true, entity); } + + if(!g_bHasOnEntitySpawned) + { + SDKHook(entity, SDKHook_SpawnPost, OnSDKHookEntitySpawnPost); + } +} + +public void OnSDKHookEntitySpawnPost(int entity) +{ + char classname[64]; + GetEntityClassname(entity, classname, sizeof(classname)); + + OnEntitySpawned(entity, classname); } public void OnEntitySpawned(int entity, const char[] classname) @@ -506,7 +570,7 @@ bool CheckEntityForLagComp(int entity, const char[] classname, bool bRecursive=f iParent = iTmp; GetEntityClassname(iParent, sParentClassname, sizeof(sParentClassname)); - if(StrEqual(sParentClassname, "player") || + if((iParent >= 1 && iParent <= MaxClients) || !strncmp(sParentClassname, "weapon_", 7)) { return false; @@ -598,7 +662,10 @@ public MRESReturn Detour_OnUTIL_Remove(Handle hParams) if(g_bCleaningUp) return MRES_Ignored; - int entity = DHookGetParam(hParams, 1); + if(DHookIsNullParam(hParams, 1)) + return MRES_Ignored; + + int entity = DHookGetParamObjectPtrVar(hParams, 1, g_iNetworkableOuter, ObjectValueType_CBaseEntityPtr); if(entity < 0 || entity > MAX_EDICTS) return MRES_Ignored; @@ -722,22 +789,6 @@ public void OnRunThinkFunctions(bool simulating) i--; continue; } - // Save old touchStamp - int touchStamp = GetEntData(g_aEntityLagData[i].iEntity, g_iTouchStamp); - g_aEntityLagData[i].iTouchStamp = touchStamp; - // We have to increase the touchStamp by 1 here to avoid breaking the touchlink. - // The touchStamp is incremented by 1 every time an entities physics are simulated. - // When two entities touch then a touchlink is created on both entities with the touchStamp of either entity. - // Usually the player would touch the trigger first and then the trigger would touch the player later on in the same frame. - // The trigger touching the player would fix up the touchStamp (which was increased by 1 by the trigger physics simulate) - // But since we're blocking the trigger from ever touching a player outside of here we need to manually increase it by 1 up front - // so the correct +1'd touchStamp is stored in the touchlink. - // After simulating the players we restore the old touchStamp (-1) and when the entity is simulated it will increase it again by 1 - // Thus both touchlinks will have the correct touchStamp value. - // The touchStamp doesn't increase when the entity is idle, however it also doesn't check untouch so we're fine. - touchStamp++; - SetEntData(g_aEntityLagData[i].iEntity, g_iTouchStamp, touchStamp); - if(g_aEntityLagData[i].iDeleted) { if(g_aEntityLagData[i].iDeleted + MAX_RECORDS <= GetGameTickCount()) @@ -767,17 +818,34 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 // this is because we simulate players first // hence no new entity record was inserted on the current tick int iGameTick = GetGameTickCount() - 1; + float fTickInterval = GetTickInterval(); - int iDelta = iGameTick - tickcount; + float fLerpTime = GetEntDataFloat(client, g_iLerpTime); + // -1 lerp ticks was determined by analyzing hits visually at host_timescale 0.01 and debug_touchlinks 1 + int iLerpTicks = RoundToFloor(0.5 + (fLerpTime / fTickInterval)) - 1; - // The user is stupid and doesn't want lag compensation. + int iTargetTick = tickcount - iLerpTicks; + int iDelta = iGameTick - iTargetTick; + + float fCorrect = 0.0; + fCorrect += GetClientLatency(client, NetFlow_Outgoing); + fCorrect += iLerpTicks * fTickInterval; + + float fDeltaTime = fCorrect - iDelta * fTickInterval; + if(FloatAbs(fDeltaTime) > 0.2) + { + // difference between cmd time and latency is too big > 200ms, use time correction based on latency + iDelta = RoundToFloor(0.5 + (fCorrect / fTickInterval)); + } + + // The player is stupid and doesn't want lag compensation. // To get the original behavior back lets assume they actually have 0 latency. - if(g_bDisableLagComp[client]) - iDelta = 0; + // To avoid abusing toggling lagcomp we increase/decrease this var by 1 every 100ms. + // This is so we only skip single ticks at a time. Fully ON = 0, Fully OFF = MAX_RECORDS + iDelta -= g_iDisableLagComp[client]; if(iDelta < 0) iDelta = 0; - if(iDelta > MAX_RECORDS) iDelta = MAX_RECORDS; @@ -793,10 +861,6 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 SetBit(g_aaFilterClientSolidTouch, client * MAX_EDICTS + iEntity); continue; } - else if(g_aEntityLagData[i].iSpawned == iPlayerSimTick) - { - ClearBit(g_aaFilterClientSolidTouch, client * MAX_EDICTS + iEntity); - } if(g_aEntityLagData[i].iDeleted) { @@ -806,6 +870,10 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 continue; } } + else + { + ClearBit(g_aaFilterClientSolidTouch, client * MAX_EDICTS + iEntity); + } if(g_aEntityLagData[i].iNotMoving >= MAX_RECORDS) continue; @@ -829,9 +897,6 @@ public void OnPostPlayerThinkFunctions() { for(int i = 0; i < g_iNumEntities; i++) { - // Restore original touchStamp - SetEntData(g_aEntityLagData[i].iEntity, g_iTouchStamp, g_aEntityLagData[i].iTouchStamp); - if(!g_aEntityLagData[i].bRestore) continue; @@ -1019,7 +1084,6 @@ bool AddEntityForLagCompensation(int iEntity, bool bLateKill) g_aEntityLagData[i].iNotMoving = MAX_RECORDS; g_aEntityLagData[i].bRestore = false; g_aEntityLagData[i].bLateKill = bLateKill; - g_aEntityLagData[i].iTouchStamp = GetEntData(iEntity, g_iTouchStamp); if(bLateKill) { @@ -1111,7 +1175,6 @@ void EntityLagData_Copy(EntityLagData obj, const EntityLagData other) obj.iSpawned = other.iSpawned; obj.iDeleted = other.iDeleted; obj.iNotMoving = other.iNotMoving; - obj.iTouchStamp = other.iTouchStamp; obj.bRestore = other.bRestore; obj.bLateKill = other.bLateKill; @@ -1241,27 +1304,30 @@ stock void PrintToBoth(const char[] format, any ...) VFormat(buffer, sizeof(buffer), format, 2); LogMessage(buffer); - for (int i = 1; i <= MaxClients; i++) + for(int client = 1; client <= MaxClients; client++) { - if (IsClientInGame(i)) + if(IsClientInGame(client)) { - PrintToConsole(i, "%s", buffer); + PrintToConsole(client, "%s", buffer); } } } -public void OnClientCookiesCached(int client) -{ - char sBuffer[16]; - GetClientCookie(client, g_hCookie_DisableLagComp, sBuffer, sizeof(sBuffer)); - if (sBuffer[0]) - g_bDisableLagComp[client] = true; - else - g_bDisableLagComp[client] = false; -} -public void OnClientDisconnect(int client) +public Action DisableLagCompTimer(Handle timer) { - g_bDisableLagComp[client] = false; + for(int client = 1; client <= MaxClients; client++) + { + if(g_bDisableLagComp[client] && g_iDisableLagComp[client] < MAX_RECORDS) + { + g_iDisableLagComp[client]++; + } + else if(!g_bDisableLagComp[client] && g_iDisableLagComp[client] > 0) + { + g_iDisableLagComp[client]--; + } + } + + return Plugin_Continue; } public Action OnLagCompSettings(int client, int args) @@ -1278,33 +1344,22 @@ public Action OnToggleLagCompSettings(int client, int args) public void ToggleLagCompSettings(int client) { - int iTimeSinceLastCommand = GetTime() - g_iLastCommandUsed[client]; - if (iTimeSinceLastCommand < 10) - { - CPrintToChat(client, "{cyan}[LagCompensation] {white}You need to wait {red}%d seconds {white}to toggle this setting again!", 10 - iTimeSinceLastCommand); - return; - } - g_bDisableLagComp[client] = !g_bDisableLagComp[client]; SetClientCookie(client, g_hCookie_DisableLagComp, g_bDisableLagComp[client] ? "1" : ""); - CPrintToChat(client, "{cyan}[LagCompensation] {white}%s.", g_bDisableLagComp[client] ? "LagCompensation Disabled" : "LagCompensation Enabled"); - g_iLastCommandUsed[client] = GetTime(); + PrintToChat(client, "\x04[LagCompensation]\x01 LagCompensation has been %s.", g_bDisableLagComp[client] ? "disabled" : "enabled"); } public void ShowSettingsMenu(int client) { Menu menu = new Menu(MenuHandler_MainMenu); - menu.SetTitle("LagCompensation Settings", client); + menu.ExitBackButton = true; char sBuffer[128]; - Format(sBuffer, sizeof(sBuffer), "LagCompensation: %s", g_bDisableLagComp[client] ? "Disabled" : "Enabled"); menu.AddItem("0", sBuffer); - menu.ExitBackButton = true; - menu.Display(client, MENU_TIME_FOREVER); } @@ -1346,11 +1401,3 @@ public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int se } } } - -stock int IsValidClient(int client, bool nobots = true) -{ - if (client <= 0 || client > MaxClients || !IsClientConnected(client) || (nobots && IsFakeClient(client))) - return false; - - return IsClientInGame(client); -} \ No newline at end of file