Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ricochet yt movement stuff PR #175

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions scripting/stac/stac_client.sp
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ void ClearClBasedVars(int userid)
cmdnumSpikeDetects [cl] = 0;
tbotDetects [cl] = -1;
invalidUsercmdDetects [cl] = 0;
invalidWishVelDetects [cl] = -1; // first detect is likely bunk
unsyncMoveDetects [cl] = 0;

// frames since client "did something"
// [ client index ][history]
Expand Down Expand Up @@ -511,6 +513,15 @@ void ClearClBasedVars(int userid)
rateFor [cl] = 0.0;
ppsFor [cl] = 0.0;

clientOS [cl] = 2;

printedOnce [cl] = false;

// STORED JOYSTICK SHIT
joystick [cl] = false;
joy_xcon [cl] = false;
waitTillNextQuery [cl] = true;

// time since the last stutter/lag spike occurred per client
timeSinceLagSpikeFor [cl] = 0.0;

Expand Down
59 changes: 56 additions & 3 deletions scripting/stac/stac_cvar_checks.sp
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,24 @@ char miscVars[][] =
// must be == 1.0
"host_timescale",
// if this is >= 8 just kick them, cathook uses this to "spoof" windows
"windows_speaker_config"
"windows_speaker_config",
// Exists on Linux only
"dxa_nullrefresh_capslock",
// Refresh this every once in a while
// (Supposedly) using the controller
"joystick",
// Controller plugged in
"joy_xcontroller_found",
// sv_force_transmit_ents ?
// sv_suppress_viewpunch ?
// tf_showspeed ?
// tf_tauntcam_* for third person ?
};

// DEFINITE cheat vars get appended to this array.
// Every cheat except cathook is smart enough to not have queryable cvars.
// Every cheat except fedoraware (dead) is smart enough to not have queryable cvars.
// For now.
// Cathook fixed their cvars being queryable but I'll keep the query in for now.
char cheatVars[][] =
{
// lith
Expand Down Expand Up @@ -296,6 +304,35 @@ public void ConVarCheck(QueryCookie cookie, int cl, ConVarQueryResult result, co
}
}

// dxa_nullrefresh_capslock
else if (StrEqual(cvarName, "dxa_nullrefresh_capslock"))
{
if (result == ConVarQuery_NotFound)
{
clientOS[cl] = 0;
}
else
{
clientOS[cl] = 1;
}
}

// joystick
else if (StrEqual(cvarName, "joystick"))
{
bool joy = (0.0 <= StringToFloat(cvarValue) < 1.0)?false:true;
joystick[cl] = joy;
joystickQueried[cl] = true;
}
// joy_xcontroller_found
else if (StrEqual(cvarName, "joy_xcontroller_found"))
{
bool joy = (0.0 <= StringToFloat(cvarValue) < 1.0)?false:true;
joy_xcon[cl] = joy;
joy_xconQueried[cl] = true;
return;
}

/*
cheat program only cvars
*/
Expand All @@ -308,7 +345,17 @@ public void ConVarCheck(QueryCookie cookie, int cl, ConVarQueryResult result, co
}
}
// log something about cvar errors
else if (result != ConVarQuery_Okay && !IsCheatOnlyVar(cvarName) && !StrEqual(cvarName, "windows_speaker_config"))
else if
(
result != ConVarQuery_Okay
&& !IsCheatOnlyVar(cvarName)
&&
(
!StrEqual(cvarName, "windows_speaker_config")
||
!StrEqual(cvarName, "dxa_nullrefresh_capslock")
)
)
{
char fmtmsg[512];
Format
Expand Down Expand Up @@ -483,6 +530,12 @@ Action Timer_CheckClientConVars(Handle timer, int userid)
// query all cvars and netprops for userid
void QueryCvarsEtc(int userid, int i)
{
// No point in running this if only one player is on.
if (GetClientCount(true) == 1 && !DEBUG)
{
return;
}

// get client index of userid
int cl = GetClientOfUserId(userid);
// don't go no further if client isn't valid!
Expand Down
15 changes: 15 additions & 0 deletions scripting/stac/stac_globals.sp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ ConVar stac_work_with_sv_cheats;




int maxInvalidWishVelDetections = 10; // Not sure what these values should be by default since they have never been widely rolled out.
int maxUnsyncMoveDetections = 10; // ^

/***** Server based stuff *****/

// tickrate stuff
Expand Down Expand Up @@ -79,6 +83,8 @@ int bhopDetects [TFMAXPLAYERS+1] = {-1, ...}; // set to -1 to ignore
int cmdnumSpikeDetects [TFMAXPLAYERS+1];
int tbotDetects [TFMAXPLAYERS+1] = {-1, ...};
int invalidUsercmdDetects [TFMAXPLAYERS+1];
int invalidWishVelDetects [TFMAXPLAYERS+1] = {-1, ...}; // first detect is likely bunk
int unsyncMoveDetects [TFMAXPLAYERS+1];

// frames since client "did something"
// [ client index ][history]
Expand Down Expand Up @@ -111,6 +117,15 @@ bool playerTaunting [TFMAXPLAYERS+1];
int playerInBadCond [TFMAXPLAYERS+1];
bool userBanQueued [TFMAXPLAYERS+1];
float sensFor [TFMAXPLAYERS+1];
int clientOS [TFMAXPLAYERS+1] = { 2, ...};

bool joystickQueried [TFMAXPLAYERS+1];
bool joy_xconQueried [TFMAXPLAYERS+1];
bool joystick [TFMAXPLAYERS+1];
bool joy_xcon [TFMAXPLAYERS+1];
bool printedOnce [TFMAXPLAYERS+1];
bool waitTillNextQuery [TFMAXPLAYERS+1] = { true, ... };

// weapon name, gets passed to aimsnap check
char hurtWeapon [TFMAXPLAYERS+1][256];
char lastCommandFor [TFMAXPLAYERS+1][256];
Expand Down
208 changes: 208 additions & 0 deletions scripting/stac/stac_onplayerruncmd.sp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
- AIM SNAPS
- FAKE ANGLES
- TURN BINDS
- BHOP CHEATS
- INVALID WISH VELOCITY (can and will false positive on +strafe (left alt key by default))
- UNSYNCHRONIZED MOVEMENT (will false positive if cl_yawspeed = 0 and client uses turnbinds (+right, +left) and +strafe.)
*/

/*
Expand Down Expand Up @@ -329,11 +332,185 @@ stock void PlayerRunCmd
aimsnapCheck(cl);
psilentCheck(cl);

invalidWishVelCheck(cl, vel[0], vel[1]); // In theory, this doesn't need to be down here. I'm only worried about halloween conditions causing issues for this.
unsynchronizedMoveCheck(cl, buttons, vel[0], vel[1]);

return;
}

/*
INVALID WISH VELOCITY CHECK
Thanks to Oryx and the devs behind it for this check.
Actually implemented it into the anticheat properly this time!
* Copyright (C) 2018 Nolan O.
* Copyright (C) 2018 shavit.
*/
void invalidWishVelCheck(int cl, float forwardmove, float sidemove)
{
int attack = 0;
if ((clbuttons[cl][0] & IN_ATTACK))
{
attack = 1;
}
else if ((clbuttons[cl][0] & IN_ATTACK2))
{
attack = 2;
}

if
(
(
// The absolute value of forwardmove and sidemove should NEVER be greater than 450 (or 450.00003 for some reason...)
(
FloatAbs(forwardmove) > 450.00003
||
FloatAbs(sidemove) > 450.00003
/*
Reasoning for the sidemove/forwardmove value of 450.00003:
Essentially, some legit clients report a value of 450.0000305175 (even happened to my client), which IS greater than 450.0. Why does this happen? No clue.
I just wanted to add a bit of leniency. Honestly, this isn't enough to cause any issues.
This could also be caused by +strafe, but who knows.
*/
)
)
&&
(
clangles[cl][1][1] != clangles[cl][0][1] // (somewhat) Workaround false positives occuring while holding +strafe. Technically may open up room for a bypass, but I have found no other solution.
)
)
{
invalidWishVelDetects[cl]++;
if (invalidWishVelDetects[cl] > 0) // First detect is ignored.
{
PrintToImportant
(
"{hotpink}[StAC]{white} Player %N {mediumpurple}has invalid wish velocity{white}!\
\nThis player is *probably* cheating, especially if they trigger this more than once.\
\nDetections so far: {palegreen}%i",
cl,
invalidWishVelDetects[cl]
);
PrintToImportant
(
"{white}Forwardmove: {palegreen}%.10f, {white}Sidemove: {palegreen}%.10f",
forwardmove,
sidemove
);
if (attack > 0)
{
PrintToImportant
(
"{hotpink}[StAC]{red} This player was ATTACKING (ATTACK%i), \
you should ban them manually with the reason \"Banned from server\"",
attack
);
}
int userid = GetClientUserId(cl);
StacLogSteam(userid);
if (invalidWishVelDetects[cl] == 1 || invalidWishVelDetects[cl] % 5 == 0)
{
char invalidWishVelInfo[128];
if (attack > 0)
{
Format
(
invalidWishVelInfo,
sizeof(invalidWishVelInfo),
"invalid wish velocity WHILE ATTACKING (attack%i, forwardmove: %.10f, sidemove %.10f)",
attack,
forwardmove,
sidemove
);
}
else
{
Format
(
invalidWishVelInfo,
sizeof(invalidWishVelInfo),
"invalid wish velocity (forwardmove: %.10f, sidemove %.10f)",
forwardmove,
sidemove
);
}
StacNotify(userid, invalidWishVelInfo, invalidWishVelDetects[cl]);
}
if (invalidWishVelDetects[cl] >= maxInvalidWishVelDetections && maxInvalidWishVelDetections > 0)
{
char reason[128];
Format(reason, sizeof(reason), "%t", "invalidWishVelBanMsg", invalidWishVelDetects[cl]);
char pubreason[256];
Format(pubreason, sizeof(pubreason), "%t", "invalidWishVelBanAllChat", cl, invalidWishVelDetects[cl]);
BanUser(userid, reason, pubreason);
}
}
}
}

/*
UNSYNCHRONIZED MOVEMENT CHECK -- Catches autostrafers
Thanks to Oryx and the devs behind it for this check.
* Copyright (C) 2018 Nolan O.
* Copyright (C) 2018 shavit.
*/
// If it was my choice, I would ban controller users and cheaters all the same since they all trigger this. Plus, controller players are annoying.
void unsynchronizedMoveCheck(int cl, int buttons, float forwardmove, float sidemove)
{
if (playerUsingController(cl))
{
return;
}

if
(
// don't bother checking if unsync'd move detection is off
maxUnsyncMoveDetections != -1
&&
// Unsynchronized usercmd->forwardmove or usercmd->sidemove.
// cl_forwardspeed and cl_sidespeed are the fully-pressed move values.
// The game will never apply them unless the buttons are added into the usercmd too. (exceptions: controllers)
// https://mxr.alliedmods.net/hl2sdk-css/source/game/client/in_main.cpp#557
// https://mxr.alliedmods.net/hl2sdk-css/source/game/client/in_main.cpp#842
(
(forwardmove == 450.0 && (buttons & IN_FORWARD) == 0) || // Check for unsynchronized forwards movement
(sidemove == -450.0 && (buttons & IN_MOVELEFT) == 0) || // Check for unsynchronized sideways (left) movement
(forwardmove == -450.0 && (buttons & IN_BACK) == 0) || // Check for unsynchronized backwards movement
(sidemove == 450.0 && (buttons & IN_MOVERIGHT) == 0) // Check for unsynchronized sideways (right) movement
)
)
{
unsyncMoveDetects[cl]++;
PrintToImportant
(
"{hotpink}[StAC]{white} Player %N {mediumpurple}had unsynchronized movement{white}!\
\nConsecutive detections so far: {palegreen}%i",
cl,
unsyncMoveDetects[cl]
);
int userid = GetClientUserId(cl);
PrintToImportant("{hotpink}[StAC]{red} Hey, since this doesn't ban automatically yet (testing mode), you should ban them manually with the reason \"Banned from server\". This goes for any detection, but especially this one.");
StacLogSteam(userid);

if (unsyncMoveDetects[cl] == 1 || unsyncMoveDetects[cl] % 5 == 0)
{
char unsyncMovInfo[128];
Format(unsyncMovInfo, sizeof(unsyncMovInfo), "unsynchronized movement");
StacNotify(userid, unsyncMovInfo, unsyncMoveDetects[cl]);
}
if (unsyncMoveDetects[cl] >= maxUnsyncMoveDetections && maxUnsyncMoveDetections > 0)
{
char reason[128];
Format(reason, sizeof(reason), "%t", "unsynchronizedMoveBanMsg", unsyncMoveDetects[cl]);
char pubreason[256];
Format(pubreason, sizeof(pubreason), "%t", "unsynchronizedMoveBanAllChat", cl, unsyncMoveDetects[cl]);
BanUser(userid, reason, pubreason);
}
}
}

/*
BHOP DETECTION - using lilac and ssac as reference, this one's better tho
There is a better way to do this without notifying the client that they have been bhop checked. (Can be abused to detect StAC running on the server) Look at Oryx/Bash2.
*/
void bhopCheck(int cl)
{
Expand Down Expand Up @@ -1291,6 +1468,37 @@ bool isTickcountRepeated(int cl)
}
*/

// I would like to check if the player has controller-like movements someday, because if this goes open source, people will force these cvars to avoid detection.
bool playerUsingController(int userid)
{
int Cl = GetClientOfUserId(userid);
// If we haven't queried these cvars from this client, we don't know if the player is using a controller or not yet.
if (!joystickQueried[Cl] || !joy_xconQueried[Cl])
{
return true;
}
// If the player has joystick set to 1 (enables controller) and has joy_xcon set to 1 (controller is plugged in), they are using a controller.
if (joystick[Cl] && joy_xcon[Cl])
{
if (!printedOnce[Cl])
{
PrintToImportant("{hotpink}[StAC]{white} Player %N {powderblue}appears to be using a controller{white}!", Cl);
StacNotify(userid, "Client appears to be using a controller");
printedOnce[Cl] = true;
}
return true;
}
// Make sure we don't detect on people who plug their controller in mid-game. This will make any checks calling this take longer to kick in, but prevent false positives.
if (waitTillNextQuery[Cl])
{
waitTillNextQuery[Cl] = false;
joystickQueried[Cl] = false;
joy_xconQueried[Cl] = false;
return true;
}
return false;
}

/********** DETECTION FORGIVENESS TIMERS **********/

// I gotta figure out a way to make these stop running after a client gets banned
Expand Down
Loading