From 906f31abe9b5ed7c76e3eea5a3a7f9ad871fed65 Mon Sep 17 00:00:00 2001
From: BotoX <github@botox.bz>
Date: Wed, 25 Sep 2019 11:37:40 +0200
Subject: [PATCH] AntiLagSwitch WIP

---
 .../gamedata/AntiLagSwitch.games.txt          | 23 ++++++
 AntiLagSwitch/scripting/AntiLagSwitch.sp      | 72 +++++++++++++++++++
 2 files changed, 95 insertions(+)
 create mode 100644 AntiLagSwitch/gamedata/AntiLagSwitch.games.txt
 create mode 100644 AntiLagSwitch/scripting/AntiLagSwitch.sp

diff --git a/AntiLagSwitch/gamedata/AntiLagSwitch.games.txt b/AntiLagSwitch/gamedata/AntiLagSwitch.games.txt
new file mode 100644
index 00000000..2138ecc7
--- /dev/null
+++ b/AntiLagSwitch/gamedata/AntiLagSwitch.games.txt
@@ -0,0 +1,23 @@
+"Games"
+{
+	"cstrike"
+	{
+		"Offsets"
+		{
+			"ProcessUsercmds"
+			{
+				"windows" 	"418"
+				"linux" 	"419"
+			}
+		}
+
+		"Signatures"
+		{
+			"RunNullCommand"
+			{
+				"library"	"server"
+				"linux"		"@_ZN11CBasePlayer14RunNullCommandEv"
+			}
+		}
+	}
+}
diff --git a/AntiLagSwitch/scripting/AntiLagSwitch.sp b/AntiLagSwitch/scripting/AntiLagSwitch.sp
new file mode 100644
index 00000000..169ea9ea
--- /dev/null
+++ b/AntiLagSwitch/scripting/AntiLagSwitch.sp
@@ -0,0 +1,72 @@
+#include <sourcemod>
+#include <sdktools>
+#include <dhooks>
+
+#pragma semicolon 1
+#pragma newdecls required
+
+public Plugin myinfo =
+{
+	name 			= "AntiLagSwitch",
+	author 			= "BotoX",
+	description 	= "",
+	version 		= "0.0",
+	url 			= ""
+};
+
+Handle g_hProcessUsercmds;
+Handle g_hRunNullCommand;
+
+public void OnPluginStart()
+{
+	Handle hGameConf = LoadGameConfigFile("AntiLagSwitch.games");
+	if(!hGameConf)
+		SetFailState("Failed to load AntiLagSwitch gamedata.");
+
+	// void CBasePlayer::RunNullCommand( void )
+	StartPrepSDKCall(SDKCall_Player);
+	if(!PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "RunNullCommand"))
+		SetFailState("PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, \"RunNullCommand\" failed!");
+
+	g_hRunNullCommand = EndPrepSDKCall();
+
+	int Offset = GameConfGetOffset(hGameConf, "ProcessUsercmds");
+	if(Offset == -1)
+		SetFailState("Failed to find ProcessUsercmds offset");
+
+	/* void CBasePlayer::ProcessUsercmds( CUserCmd *cmds, int numcmds, int totalcmds,
+	int dropped_packets, bool paused ) */
+	g_hProcessUsercmds = DHookCreate(Offset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, Hook_ProcessUsercmds);
+	if(g_hProcessUsercmds == INVALID_HANDLE)
+		SetFailState("Failed to DHookCreate ProcessUsercmds");
+
+	DHookAddParam(g_hProcessUsercmds, HookParamType_ObjectPtr);	// 1 - CUserCmd *cmds
+	DHookAddParam(g_hProcessUsercmds, HookParamType_Int);		// 2 - int numcmds
+	DHookAddParam(g_hProcessUsercmds, HookParamType_Int);		// 3 - int totalcmds
+	DHookAddParam(g_hProcessUsercmds, HookParamType_Int);		// 4 - int dropped_packets
+	DHookAddParam(g_hProcessUsercmds, HookParamType_Bool);		// 5 - bool paused
+
+	delete hGameConf;
+
+	// Late load.
+	for(int client = 1; client <= MaxClients; client++)
+	{
+		if(IsClientInGame(client))
+			OnClientPutInServer(client);
+	}
+}
+
+public void OnClientPutInServer(int client)
+{
+	DHookEntity(g_hProcessUsercmds, true, client);
+}
+
+public MRESReturn Hook_ProcessUsercmds(int client, Handle hParams)
+{
+
+}
+
+int RunNullCommand(int client)
+{
+	return SDKCall(g_hRunNullCommand, client);
+}