Files
AI_Aimbot_Detecter/ai.sp
Huoji's e24baaf6f7 make to English version
make to English version
2020-10-11 19:43:24 +08:00

336 lines
10 KiB
SourcePawn

#pragma semicolon 1
#pragma newdecls required
/* SM Includes */
#include <sourcemod>
#include <sdktools>
#include <sdktools_gamerules>
#define TIME_TO_TICK(%1) (RoundToNearest((%1) / GetTickInterval()))
#define TICK_TO_TIME(%1) ((%1) * GetTickInterval())
#define IS_CLIENT(%1) (1 <= %1 <= MaxClients)
#define ABS(%1) ((%1)>0 ? (%1) : -(%1))
/* Plugin Info */
public Plugin myinfo =
{
name = "Crow Aimbot Detector",
author = "huoji",
description = "Analyzes clients to detect aimbots",
version = "0.0.1",
url = "http://key08.com/"
};
/* Globals */
#define AIM_ANGLE_CHANGE 15 // Max angle change that a player should snap
#define AIM_BAN_MIN 4 // Minimum number of detections before an auto-ban is allowed
#define AIM_MIN_DISTANCE 50.0 // Minimum distance acceptable for a detection.
Handle g_IgnoreWeapons = INVALID_HANDLE;
float g_fEyeAngles[MAXPLAYERS+1][64][3];
float g_Sensitivity[MAXPLAYERS + 1];
float g_mYaw[MAXPLAYERS + 1];
float g_mPitch[MAXPLAYERS + 1];
int g_iEyeIndex[MAXPLAYERS+1];
int g_iMouse[MAXPLAYERS+1][64][2];
int g_iAimDetections[MAXPLAYERS+1];
int g_iAimbotBan = 0;
int g_iMaxAngleHistory;
int g_cheat = 0;
bool g_bIsShoting[MAXPLAYERS+1][64];
/* Plugin Functions */
public void OnPluginStart()
{
// Store no more than 300ms worth of angle history.
if ((g_iMaxAngleHistory = TIME_TO_TICK(0.3)) > sizeof(g_fEyeAngles[]))
{
g_iMaxAngleHistory = sizeof(g_fEyeAngles[]);
}
// Weapons to ignore when analyzing.
g_IgnoreWeapons = CreateTrie();
SetTrieValue(g_IgnoreWeapons, "weapon_knife", 1);
SetTrieValue(g_IgnoreWeapons, "weapon_taser", 1);
// Hooks.
HookEntityOutput("trigger_teleport", "OnEndTouch", Teleport_OnEndTouch);
HookEvent("player_spawn", Event_PlayerSpawn, EventHookMode_Post);
HookEvent("player_death", Event_PlayerDeath, EventHookMode_Post);
HookEventEx("cs_intermission", Event_Intermission);
g_cheat = CreateConVar("sm_crowai_cheat", "0", "0 = no cheat , 1 = cheating.", _, true, 0.0, true, 1.0);
PrintToServer("[CrowAi] Init Success!");
}
void OnFileUploadCallBack(HTTPStatus status, any value)
{
PrintToServer("Upload complete");
}
public Action Event_Intermission(Handle event, const char[] name, bool dontBroadcast)
{
PrintToChatAll("比赛结束!上传反作弊数据中!");
//upload your saved data
return Plugin_Continue;
}
stock bool IsClientNew(int client)
{
// Client must be ingame.
return IsFakeClient(client) || GetGameTime() > GetClientTime(client);
}
stock void ZeroVector(float vec[3])
{
vec[0] = vec[1] = vec[2] = 0.0;
}
stock bool IsVectorZero(const float vec[3])
{
return vec[0] == 0.0 && vec[1] == 0.0 && vec[2] == 0.0;
}
public void OnClientPutInServer(int client)
{
if (IsClientNew(client))
{
g_iAimDetections[client] = 0;
Aimbot_ClearAngles(client);
}
}
public void Teleport_OnEndTouch(const char[] output, int caller, int activator, float delay)
{
/* A client is being teleported in the map. */
if (IS_CLIENT(activator) && IsClientConnected(activator))
{
Aimbot_ClearAngles(activator);
CreateTimer(0.1 + delay, Timer_ClearAngles, GetClientUserId(activator), TIMER_FLAG_NO_MAPCHANGE);
}
}
public Action Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast)
{
int userid = event.GetInt("userid");
int client = GetClientOfUserId(userid);
if (IS_CLIENT(client))
{
Aimbot_ClearAngles(client);
CreateTimer(0.1, Timer_ClearAngles, userid, TIMER_FLAG_NO_MAPCHANGE);
}
}
public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)
{
char sWeapon[32], dummy;
//GetEventString(event, "weapon", sWeapon, sizeof(sWeapon));
event.GetString("weapon", sWeapon, sizeof(sWeapon));
if (GetTrieValue(g_IgnoreWeapons, sWeapon, dummy))
{
return;
}
if (GameRules_GetProp("m_bWarmupPeriod") == 1)
{
return;
}
int victim = GetClientOfUserId(event.GetInt("userid"));
int attacker = GetClientOfUserId(event.GetInt("attacker"));
if (IS_CLIENT(attacker) && victim != attacker && IsClientInGame(attacker))
{
float vVictim[3], vAttacker[3];
GetClientAbsOrigin(victim, vVictim);
GetClientAbsOrigin(attacker, vAttacker);
if (GetVectorDistance(vVictim, vAttacker) >= AIM_MIN_DISTANCE)
{
Aimbot_AnalyzeAngles(attacker);
}
}
}
public Action Timer_ClearAngles(Handle timer, any userid)
{
/* Delayed because the client's angles can sometimes "spin" after being teleported. */
int client = GetClientOfUserId(userid);
if (IS_CLIENT(client))
{
Aimbot_ClearAngles(client);
}
return Plugin_Stop;
}
public Action Timer_DecreaseCount(Handle timer, any userid)
{
/* Decrease the detection count by 1. */
int client = GetClientOfUserId(userid);
if (IS_CLIENT(client) && g_iAimDetections[client])
{
g_iAimDetections[client]--;
}
return Plugin_Stop;
}
int m_iShotsFired(int client)
{
return GetEntPropEnt(client, Prop_Send, "m_iShotsFired");
}
float m_aimPunchAngleX(int client)
{
float punch[3];
GetEntPropVector(client, Prop_Send, "m_aimPunchAngle",punch);
return punch[0];
}
float m_aimPunchAngleY(int client)
{
float punch[3];
GetEntPropVector(client, Prop_Send, "m_aimPunchAngle",punch);
return punch[1];
}
public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2])
{
g_fEyeAngles[client][g_iEyeIndex[client]] = angles;
g_iMouse[client][g_iEyeIndex[client]] = mouse;
g_bIsShoting[client][g_iEyeIndex[client]] = false;
if(m_iShotsFired(client) > 2)
{
g_fEyeAngles[client][g_iEyeIndex[client]][0] += m_aimPunchAngleX(client) * 2;
g_fEyeAngles[client][g_iEyeIndex[client]][1] += m_aimPunchAngleY(client) * 2;
g_bIsShoting[client][g_iEyeIndex[client]] = true;
}
if (++g_iEyeIndex[client] == g_iMaxAngleHistory)
{
g_iEyeIndex[client] = 0;
}
return Plugin_Continue;
}
public void ConVar_QueryClient(QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue)
{
if(!IsFakeClient(client))
{
if(result == ConVarQuery_Okay)
{
if(StrEqual("sensitivity", cvarName))
{
g_Sensitivity[client] = StringToFloat(cvarValue);
}else if(StrEqual("m_yaw", cvarName))
{
g_mYaw[client] = StringToFloat(cvarValue);
}
else if(StrEqual("m_pitch", cvarName))
{
g_mPitch[client] = StringToFloat(cvarValue);
}
}
}
}
void Aimbot_AnalyzeAngles(int client)
{
if(IsFakeClient(client))
return;
/* Analyze the client to see if their angles snapped. */
float vLastAngles[3], vAngles[3], fAngleDiff,Last_AngleDiff;
int idx = g_iEyeIndex[client];
QueryClientConVar(client, "sensitivity", ConVar_QueryClient, client);
QueryClientConVar(client, "m_yaw", ConVar_QueryClient, client);
QueryClientConVar(client, "m_pitch", ConVar_QueryClient, client);
int num_of_detect = 0;
int num_of_detect_smooth = 0;
//PrintToChatAll("[CrowAntiCheat] 开始分析 %N",client);
char steamid[64];
GetClientAuthId(client, AuthId_SteamID64, steamid, sizeof(steamid));
char path_name[PLATFORM_MAX_PATH];
Format(path_name, sizeof(path_name), "addons\\sourcemod\\ai\\ai_%s.csv",steamid);
bool file_exists = true;
if(!FileExists(path_name)){
file_exists = false;
}
Handle handle_file = OpenFile(path_name, "a+");
char file_head[19999];
if(file_exists == false){
bool first_meme = false;
for (int i = 0; i < g_iMaxAngleHistory; i++)
{
if (i == 0)
{
continue;
}
if(first_meme == false){
first_meme = true;
Format(file_head, sizeof(file_head), "%d_x,%d_y,%d_diff,%d_mx,%d_my",i,i,i,i,i);
}else{
Format(file_head, sizeof(file_head), "%s,%d_x,%d_y,%d_diff,%d_mx,%d_my",file_head,i,i,i,i,i);
}
}
WriteFileLine(handle_file, "%s,is_cheat",file_head);
//PrintToChatAll("max_angle_tick: %d",g_iMaxAngleHistory);
}
bool first_meme2 = false;
char cheat_data[19999];
for (int i = 0; i < g_iMaxAngleHistory; i++)
{
if (idx == g_iMaxAngleHistory)
{
idx = 0;
}
if (IsVectorZero(g_fEyeAngles[client][idx]))
{
break;
}
// Nothing to compare on the first iteration.
if (i == 0)
{
vLastAngles = g_fEyeAngles[client][idx];
idx++;
continue;
}
vAngles = g_fEyeAngles[client][idx];
fAngleDiff = GetVectorDistance(vLastAngles, vAngles);
// If the difference is being reported higher than 180, get the 'real' value.
if (fAngleDiff > 180)
{
fAngleDiff = FloatAbs(fAngleDiff - 360);
}
if (fAngleDiff > AIM_ANGLE_CHANGE)
{
PrintToChatAll("[CrowAI] %N rage aimbot skip this data",client);
CloseHandle(handle_file);
return;
}
int mouse[2];
mouse = g_iMouse[client][idx];
if(first_meme2 == false){
first_meme2 = true;
Format(cheat_data, sizeof(cheat_data), "%f,%f,%f,%d,%d",g_fEyeAngles[client][idx][0],g_fEyeAngles[client][idx][1],fAngleDiff,mouse[0],mouse[1]);
}else{
Format(cheat_data, sizeof(cheat_data), "%s,%f,%f,%f,%d,%d",cheat_data,g_fEyeAngles[client][idx][0],g_fEyeAngles[client][idx][1],fAngleDiff,mouse[0],mouse[1]);
}
vLastAngles = vAngles;
Last_AngleDiff = fAngleDiff;
idx++;
}
int is_cheat = GetConVarInt(g_cheat);
WriteFileLine(handle_file, "%s,%d",cheat_data,is_cheat);
//PrintToChatAll("[CrowAI] %N 分析完毕",client);
CloseHandle(handle_file);
}
void Aimbot_ClearAngles(int client)
{
/* Clear angle history and reset the index. */
g_iEyeIndex[client] = 0;
for (int i = 0; i < g_iMaxAngleHistory; i++)
{
ZeroVector(g_fEyeAngles[client][i]);
g_iMouse[client][i][0] = 0;
g_iMouse[client][i][1] = 0;
}
}