summaryrefslogtreecommitdiff
path: root/sourcemod/scripting/gokz-jumpstats/jump_validating.sp
blob: c6835c7cea8c841a934ea3f3481f3b1a3a01766f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
	Invalidating invalid jumps, such as ones with a modified velocity.
*/

static Handle processMovementHookPost;

void OnPluginStart_JumpValidating()
{
	Handle gamedataConf = LoadGameConfigFile("gokz-core.games");
	if (gamedataConf == null)
	{
		SetFailState("Failed to load gokz-core gamedata");
	}
	
	// CreateInterface
	// Thanks SlidyBat and ici
	StartPrepSDKCall(SDKCall_Static);
	if (!PrepSDKCall_SetFromConf(gamedataConf, SDKConf_Signature, "CreateInterface"))
	{
		SetFailState("Failed to get CreateInterface");
	}
	PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
	PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL);
	PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
	Handle CreateInterface = EndPrepSDKCall();
	
	if (CreateInterface == null)
	{
		SetFailState("Unable to prepare SDKCall for CreateInterface");
	}
	
	char interfaceName[64];
	
	// ProcessMovement
	if (!GameConfGetKeyValue(gamedataConf, "IGameMovement", interfaceName, sizeof(interfaceName)))
	{
		SetFailState("Failed to get IGameMovement interface name");
	}
	Address IGameMovement = SDKCall(CreateInterface, interfaceName, 0);
	if (!IGameMovement)
	{
		SetFailState("Failed to get IGameMovement pointer");
	}
	
	int offset = GameConfGetOffset(gamedataConf, "ProcessMovement");
	if (offset == -1)
	{
		SetFailState("Failed to get ProcessMovement offset");
	}

	processMovementHookPost = DHookCreate(offset, HookType_Raw, ReturnType_Void, ThisPointer_Ignore, DHook_ProcessMovementPost);
	DHookAddParam(processMovementHookPost, HookParamType_CBaseEntity);
	DHookAddParam(processMovementHookPost, HookParamType_ObjectPtr);
	DHookRaw(processMovementHookPost, false, IGameMovement);
}

static MRESReturn DHook_ProcessMovementPost(Handle hParams)
{
	int client = DHookGetParam(hParams, 1);
	if (!IsValidClient(client) || IsFakeClient(client))
	{
		return MRES_Ignored;
	}
	float pVelocity[3], velocity[3];
	Movement_GetProcessingVelocity(client, pVelocity);
	Movement_GetVelocity(client, velocity);

	gB_SpeedJustModifiedExternally[client] = false;
	for (int i = 0; i < 3; i++)
	{
		if (FloatAbs(pVelocity[i] - velocity[i]) > EPSILON)
		{
			// The current velocity doesn't match the velocity of the end of movement processing,
			// so it must have been modified by something like a trigger.
			InvalidateJumpstat(client);
			gB_SpeedJustModifiedExternally[client] = true;
			break;
		}
	}

	return MRES_Ignored;
}