/* AMX Mod X
* HL Anticheat
*
*
http://aghl.ru/forum/ - Russian Half-Life and Adrenaline Gamer Community
*
* This file is provided as is (no warranties)
*/
#include <amxmodx>
#include <amxmisc>
#include <fakemeta_util>
#include <hamsandwich>
#define PLUGIN "HL Anticheat"
#define VERSION "1.0"
#define AUTHOR "Aghl.ru Team"
#define MAX_PLAYERS 32
#define PREFIX "[HL Anticheat]"
#define DIR_CONF "hl_anticheat"
#define DIR_DLL "opengl"
#define DIR_LOGS "logs"
#define FILE_OPENGL "../opengl32.dll"
#define FILE_SETTINGS "settings.ini"
#define FILE_ALIASES "aliases.ini"
#define FILE_WHITELIST "whitelist.ini"
#define FILE_CHECK "files_check.ini"
#define TASK_START 393712
#define TASK_ALIAS 592369
#define TASK_LAMP 936812
#define is_user_valid_connected(%1) (1 <= %1 <= g_MaxPlayers && check_bit(g_bit_is_connected,%1))
#define check_bit(%1,%2) (%1 & (1<<%2))
#define set_bit(%1,%2) (%1 |= (1<<%2))
#define clr_bit(%1,%2) (%1 &= ~(1<<%2))
enum _:NOTIFY
{
NOTIFY_ALL_CHAT, // 1
NOTIFY_ALL_HUD, // 2
NOTIFY_CHEATER_HUD, // 4
NOTIFY_ADMIN_HUD, // 8
NOTIFY_CHEATER_CHAT, // 16
NOTIFY_ADMIN_CHAT // 32
}
enum _:BAN
{
KICK,
BAN_IP,
BAN_ADVANCED,
BAN_AMXBANS_5,
BAN_AMXBANS_6,
BAN_CUSTOM
}
enum _:DETECTIONS
{
DET_OPENGL,
DET_FUPD_SPAM,
DET_MODEL,
DET_LAMPING,
DET_SPEED
}
enum _:GHOST
{
GHOST_EXPLOSIVE,
GHOST_GAUSS
}
enum _:RESP
{
RESP_TRIPMINE,
RESP_SATCHEL
}
new
g_BanSystem = -1, g_bit_immunity, g_bit_is_connected, g_MaxPlayers,
g_pSearch, gm_ent, HamHook:g_Ham_TraceAttack,
g_alias_check_runing[MAX_PLAYERS + 1],
g_alias[MAX_PLAYERS + 1],
g_alias_control[MAX_PLAYERS + 1],
g_alias_progress[MAX_PLAYERS + 1],
g_alias_repeat[MAX_PLAYERS + 1],
g_Detections[MAX_PLAYERS + 1][DETECTIONS],
Array: g_Aliases, g_AliasesSize, g_CustomAliases, Trie: g_WhiteList,
g_CvarNotify, g_CvarNotifyHud, g_CvarLog, g_CvarBanSystem,
g_CvarAlias, g_CvarAliasPunish, g_CvarProtector, g_CvarProtectorPunish,
g_CvarCdhack, g_CvarCdhackPunish, g_CvarOpengf, g_CvarOpengfPunish,
g_CvarProxy, g_CvarProxyPunish, g_CvarOpenGL, g_CvarOpenGLPunish,
g_CvarGMblocker, g_CvarLampGuard, g_CvarLampPunish, g_CvarRespGuard,
g_CvarSatchelRadius, g_CvarTripmineRadius
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
register_clcmd("fullupdate", "fullupdate_hook")
RegisterHam(Ham_Think, "monster_snark", "fw_SnarkThinkPre")
register_forward(FM_ClientUserInfoChanged, "fw_ClientUserInfoChanged")
//register_forward(FM_CmdStart, "fw_cmdstart")
}
new Float: g_playerTime[MAX_PLAYERS + 1]
new g_cmdCount[MAX_PLAYERS + 1]
public client_connect(id)
{
g_playerTime[id] = 0.0
g_cmdCount[id] = 0
}
public fw_cmdstart(id, uc, seed)
{
if(is_user_valid_connected(id) && !check_bit(g_bit_immunity, id) && ExecuteHam(Ham_IsAlive, id))
{
//client_print(id, print_chat, "detec %d", g_Detections[id][DET_SPEED])
g_cmdCount[id]++
static msec, Float:time
msec = get_uc(uc, UC_Msec)
time = get_gametime()
if (!g_playerTime[id] || g_playerTime[id] < (time - 1))
{
//server_print("Time correction: id: %d, dt: +%f", id, time - _playerTime[id]);
g_playerTime[id] = time
}
g_playerTime[id] += msec / 1000.0
/*
if (_prevGameTime > time)
server_print("id: %d, c: %5d, ms: %2d, gt: %f, pt: %f, btn: %d <------", id, _cmdCount[id], msec, time, _playerTime[id], btn);
else
server_print("id: %d, c: %5d, ms: %2d, gt: %f, pt: %f, btn: %d", id, _cmdCount[id], msec, time, _playerTime[id], btn);
_prevGameTime = time;
*/
g_Detections[id][DET_SPEED] <= 0 ? g_Detections[id][DET_SPEED] : g_Detections[id][DET_SPEED]--
if (g_playerTime[id] > (time + 0.2) && get_uc(uc, UC_Buttons))
{
g_Detections[id][DET_SPEED] += 3
//server_print("%d", g_Detections[id][DET_SPEED] )
/*server_print("-----------------------------------");
server_print("SpeedHack detected: id: %d", id);
server_print("-----------------------------------");
server_print("Time correction: id: %d, dt: %f", id, time - _playerTime[id]);
_playerTime[id] = time;*/
if(g_Detections[id][DET_SPEED] >= 250)
{
ban_user(id, -1, "SpeedHack Detected")
//notify_detection(id, "SpeedHack Detected")
}
}
}
return FMRES_IGNORED
}
enum MODEL
{
MODEL_MDL[32],
MODEL_TOPCOLOR[32],
MODEL_BOTTOMCOLOR[32]
}
new g_PlayersModels[MAX_PLAYERS + 1][MODEL]
public fw_ClientUserInfoChanged(id, buffer)
{
if(!is_user_valid_connected(id))
return FMRES_IGNORED
static val_model[32], val_top[32], val_bottom[32]
engfunc(EngFunc_InfoKeyValue, buffer, "model", val_model, charsmax(val_model))
engfunc(EngFunc_InfoKeyValue, buffer, "topcolor", val_top, charsmax(val_top))
engfunc(EngFunc_InfoKeyValue, buffer, "bottomcolor", val_bottom, charsmax(val_bottom))
if(equali(val_model, g_PlayersModels[id][MODEL_MDL]) && equali(val_top, g_PlayersModels[id][MODEL_TOPCOLOR]) && equali(val_bottom, g_PlayersModels[id][MODEL_BOTTOMCOLOR]))
return FMRES_IGNORED
else
{
if(g_Detections[id][DET_MODEL]++ >= 20)
{
set_user_info(id, "model", g_PlayersModels[id][MODEL_MDL])
set_user_info(id, "topcolor", g_PlayersModels[id][MODEL_TOPCOLOR])
set_user_info(id, "bottomcolor", g_PlayersModels[id][MODEL_BOTTOMCOLOR])
return FMRES_SUPERCEDE
}
}
engfunc(EngFunc_InfoKeyValue, buffer, "model", g_PlayersModels[id][MODEL_MDL], charsmax(g_PlayersModels[]))
engfunc(EngFunc_InfoKeyValue, buffer, "topcolor", g_PlayersModels[id][MODEL_TOPCOLOR], charsmax(g_PlayersModels[]))
engfunc(EngFunc_InfoKeyValue, buffer, "bottomcolor", g_PlayersModels[id][MODEL_BOTTOMCOLOR], charsmax(g_PlayersModels[]))
return FMRES_IGNORED
}
#define SATCHEL_CHECKED pev_iuser4
#define OFFSET_AMMO_TRIPMINE 317
#define OFFSET_AMMO_SNARK 320
#define EXTRAOFFSET 5
stock bool:_fm_is_ent_visible(index, entity, ignoremonsters = 0)
{
static Float:start[3], Float:dest[3]
pev(index, pev_origin, start)
pev(index, pev_view_ofs, dest)
xs_vec_add(start, dest, start)
pev(entity, pev_origin, dest)
engfunc(EngFunc_TraceLine, start, dest, ignoremonsters, index, 0)
static Float:fraction
get_tr2(0, TR_flFraction, fraction)
if (fraction == 1.0 || get_tr2(0, TR_pHit) == entity)
return true
return false
}
public fw_SatchelThinkPre(satchel_ent)
{
if(!pev_valid(satchel_ent) || pev(satchel_ent, SATCHEL_CHECKED))
return HAM_IGNORED
static Float: velocity[3]
pev(satchel_ent, pev_velocity, velocity)
if(velocity[0] || velocity[1] || velocity[2])
return HAM_IGNORED
static origin[3], ent
pev(satchel_ent, pev_origin, origin)
set_pev(satchel_ent, SATCHEL_CHECKED, 1)
ent = -1
while((ent = engfunc(EngFunc_FindEntityInSphere, ent, origin, float(get_pcvar_num(g_CvarSatchelRadius)))) != 0)
{
if(pev_valid(ent))
{
static classname[32]
pev(ent, pev_classname, classname, charsmax(classname))
if((equal(classname, "info_player_deathmatch") || equal(classname, "info_player_start")) && _fm_is_ent_visible(satchel_ent, ent, 1))
{
new id = pev(satchel_ent, pev_owner)
if(is_user_valid_connected(id) && ExecuteHam(Ham_IsAlive, id))
{
set_pdata_int(id, OFFSET_AMMO_TRIPMINE + 1, get_pdata_int(id,OFFSET_AMMO_TRIPMINE + 1, EXTRAOFFSET) + 1, EXTRAOFFSET)
set_hudmessage(0, 255, 0, -1.0, 0.88, 1, 1.0, 4.0, 0.05, 0.2, -1)
show_hudmessage(id, "Respawn Guard: satchel removed!")
}
engfunc(EngFunc_RemoveEntity, satchel_ent)
return HAM_SUPERCEDE
}
}
}
return HAM_IGNORED
}
public fw_TripmineSpawnPre(mine_ent)
{
if(!pev_valid(mine_ent))
return HAM_IGNORED
static origin[3], ent
pev(mine_ent, pev_origin, origin)
ent = -1
while((ent = engfunc(EngFunc_FindEntityInSphere, ent, origin, float(get_pcvar_num(g_CvarTripmineRadius)))) != 0)
{
if(pev_valid(ent))
{
static classname[32]
pev(ent, pev_classname, classname, charsmax(classname))
if((equal(classname, "info_player_deathmatch") || equal(classname, "info_player_start")) && _fm_is_ent_visible(mine_ent, ent, 1))
{
new id = pev(mine_ent, pev_owner)
if(is_user_valid_connected(id) && ExecuteHam(Ham_IsAlive, id) && get_user_weapon(id) == HLW_TRIPMINE)
{
set_pdata_int(id, OFFSET_AMMO_TRIPMINE, get_pdata_int(id, OFFSET_AMMO_TRIPMINE, EXTRAOFFSET) + 1, EXTRAOFFSET)
set_hudmessage(0, 255, 0, -1.0, 0.88, 1, 1.0, 4.0, 0.05, 0.2, -1)
show_hudmessage(id, "Respawn Guard: tripmine removed!")
}
return HAM_SUPERCEDE
}
}
}
return HAM_IGNORED
}
public fw_SnarkThinkPre(snark_ent)
{
if(!pev_valid(snark_ent))
return HAM_IGNORED
static Float: velocity[3]
pev(snark_ent, pev_velocity, velocity)
if(velocity[0] || velocity[1] || velocity[2])
{
if(pev(snark_ent, pev_solid) != SOLID_BBOX)
set_pev(snark_ent, pev_solid, SOLID_BBOX)
return HAM_IGNORED
}
else
{
if(pev(snark_ent, pev_solid) != SOLID_NOT)
set_pev(snark_ent, pev_solid, SOLID_NOT)
return HAM_IGNORED
}
return HAM_IGNORED
}
public fw_TraceLine(Float:start[3], Float:dest[3], ignore_monsters, ent, ptr)
{
if(!pev_valid(ent) || !pev_valid(g_pSearch))
return FMRES_IGNORED
static ent2; ent2 = get_tr2(ptr, TR_pHit)
static StartSolid, AllSolid, InOpen, flFraction
StartSolid = get_tr2(ptr, TR_StartSolid)
AllSolid = get_tr2(ptr, TR_AllSolid)
InOpen = get_tr2(ptr, TR_InOpen)
get_tr2(ptr, TR_flFraction, flFraction)
if((flFraction >= 1.0 || ent2 == g_pSearch) && StartSolid)
{
if((!AllSolid || InOpen) || (AllSolid && flFraction >= 1.0))
{
EnableHamForward(g_Ham_TraceAttack)
gm_ent = ent
return FMRES_IGNORED
}
}
g_pSearch = FM_NULLENT
gm_ent = FM_NULLENT
return FMRES_IGNORED
}
public fw_FindEntityInSphere(start, Float:origin[3], Float:radius)
{
g_pSearch = get_orig_retval()
}
public lamp_guard(id)
{
id -= TASK_LAMP
if(g_Detections[id][DET_LAMPING] > 140)
g_Detections[id][DET_LAMPING] = 140
else if(g_Detections[id][DET_LAMPING] > 0)
g_Detections[id][DET_LAMPING] -= 3
else
{
g_Detections[id][DET_LAMPING] = 0
remove_task(id + TASK_LAMP)
return
}
set_task(3.0, "lamp_guard", id + TASK_LAMP)
}
public fw_TraceAttack(ent, attacker, Float: damage, Float: direction[3], trace, damagebits)
{
DisableHamForward(g_Ham_TraceAttack)
if(gm_ent && attacker && gm_ent == attacker)
{
gm_ent = FM_NULLENT
new classname[32]
pev(attacker, pev_classname, classname, charsmax(classname))
if(equali(classname, "weapon_gauss"))
{
if(check_bit(get_pcvar_num(g_CvarGMblocker), GHOST_GAUSS))
return HAM_SUPERCEDE
if(get_pcvar_num(g_CvarLampGuard))
{
new id = pev(attacker, pev_owner)
if(is_user_valid_connected(id) || !check_bit(g_bit_immunity, id))
{
g_Detections[id][DET_LAMPING] += 15
!task_exists(id + TASK_LAMP) ? set_task(3.0, "lamp_guard", id + TASK_LAMP) : change_task(id + TASK_LAMP, 10.0)
if(g_Detections[id][DET_LAMPING] >= 140)
{
notify_detection(id, "Lamping Detected")
ban_user(id, get_pcvar_num(g_CvarLampPunish), "Lamping Detected")
return HAM_SUPERCEDE
}
else if(g_Detections[id][DET_LAMPING] >= 100)
{
set_hudmessage(255, 0, 0, -1.0, 0.88, 1, 1.0, 12.0, 0.05, 0.2, -1)
show_hudmessage(id, "Lamp Guard: 100%% warning", g_Detections[id][DET_LAMPING])
return HAM_SUPERCEDE
}
else if(20 <= g_Detections[id][DET_LAMPING] < 100)
{
switch(g_Detections[id][DET_LAMPING])
{
case 20..60: set_hudmessage(0, 255, 0, -1.0, 0.88, 1, 1.0, 12.0, 0.05, 0.2, -1)
default: set_hudmessage(255, 0, 0, -1.0, 0.88, 1, 1.0, 12.0, 0.05, 0.2, -1)
}
show_hudmessage(id, "Lamp Guard: %d%% warning", g_Detections[id][DET_LAMPING])
}
}
}
}
else if(check_bit(get_pcvar_num(g_CvarGMblocker), GHOST_EXPLOSIVE))
return HAM_SUPERCEDE
}
return HAM_IGNORED
}
register_cvars()
{
g_CvarBanSystem = register_cvar("hl_ac_ban_system", "10")
g_CvarNotify = register_cvar("hl_ac_notify", "13")
g_CvarNotifyHud = register_cvar("hl_ac_notify_hud", "255 0 0 -1.0 0.35 1 1.0 12.0 0.05 0.2")
g_CvarLog = register_cvar("hl_ac_log", "1")
g_CvarProtector = register_cvar("hl_ac_hlprotector", "1")
g_CvarProtectorPunish = register_cvar("hl_ac_hlprotector_bantime", "7200")
g_CvarProxy = register_cvar("hl_ac_hlproxy", "1")
g_CvarProxyPunish = register_cvar("hl_ac_hlproxy_bantime", "7200")
g_CvarCdhack = register_cvar("hl_ac_cdhack", "1")
g_CvarCdhackPunish = register_cvar("hl_ac_cdhack_bantime", "0")
g_CvarOpengf = register_cvar("hl_ac_opengf32", "1")
g_CvarOpengfPunish = register_cvar("hl_ac_opengf32_bantime", "0")
g_CvarOpenGL = register_cvar("hl_ac_opengl", "1")
g_CvarOpenGLPunish = register_cvar("hl_ac_opengl_bantime", "0")
g_CvarAlias = register_cvar("hl_ac_alias", "1")
g_CvarAliasPunish = register_cvar("hl_ac_alias_bantime", "7200")
g_CvarGMblocker = register_cvar("hl_ac_ghostmining_block", "1")
g_CvarLampGuard = register_cvar("hl_ac_lamp_guard", "1")
g_CvarLampPunish = register_cvar("hl_ac_lamp_guard_bantime", "-1")
g_CvarRespGuard = register_cvar("hl_ac_respawn_guard", "3")
g_CvarTripmineRadius = register_cvar("hl_ac_tripmine_radius", "100")
g_CvarSatchelRadius = register_cvar("hl_ac_satchel_radius", "125")
}
public fullupdate_hook(id)
{
if(g_Detections[id][DET_FUPD_SPAM] ++ > 40)
ban_user(id, -1, "Fullupdate Spam Detected")
}
public plugin_precache()
{
if(!is_running("valve"))
{
new error[64], mod[32]; get_modname(mod, charsmax(mod))
formatex(error, charsmax(error), "Unsupported mod ^"%s^"", mod)
set_fail_state(error)
}
server_cmd("mp_consistency 1")
new PluginConfDir[512]; get_localinfo("amx_configdir", PluginConfDir, charsmax(PluginConfDir))
format(PluginConfDir, charsmax(PluginConfDir), "%s/%s", PluginConfDir, DIR_CONF)
register_cvars()
config_load(PluginConfDir)
load_aliases(PluginConfDir)
load_white_list(PluginConfDir)
load_files_check(PluginConfDir)
if(get_pcvar_num(g_CvarOpenGL))
{
opengl_load_dll(PluginConfDir)
if(file_exists(FILE_OPENGL))
force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, FILE_OPENGL)
}
/*if(get_pcvar_num(g_CvarGMblocker) || get_pcvar_num(g_CvarLampGuard))
{
register_forward(FM_FindEntityInSphere, "fw_FindEntityInSphere", 1)
register_forward(FM_TraceLine, "fw_TraceLine", 1)
g_Ham_TraceAttack = RegisterHam(Ham_TraceAttack, "player", "fw_TraceAttack")
DisableHamForward(g_Ham_TraceAttack)
}*/
new resp_guard = get_pcvar_num(g_CvarRespGuard)
if(resp_guard)
{
if(check_bit(resp_guard, RESP_TRIPMINE))
RegisterHam(Ham_Spawn, "monster_tripmine", "fw_TripmineSpawnPre")
if(check_bit(resp_guard, RESP_SATCHEL))
RegisterHam(Ham_Think, "monster_satchel", "fw_SatchelThinkPre")
}
g_MaxPlayers = get_maxplayers()
}
public plugin_end()
{
ArrayDestroy(g_Aliases)
TrieDestroy(g_WhiteList)
}
public client_disconnect(id)
{
clr_bit(g_bit_immunity,id);
clr_bit(g_bit_is_connected, id)
g_alias_check_runing[id] = 0
g_alias[id] = 0
g_alias_control[id] = 0
g_alias_progress[id] = 0
g_alias_repeat[id] = 0
for(new i = 0; i < DETECTIONS; i++)
g_Detections[id][i] = 0
remove_task(id + TASK_START)
remove_task(id + TASK_ALIAS)
remove_task(id + TASK_LAMP)
}
public inconsistent_file(id, const filename[], reason[64])
{
if(equali(filename, FILE_OPENGL))
{
g_Detections[id][DET_OPENGL] = 1
return PLUGIN_HANDLED
}
return PLUGIN_CONTINUE
}
public client_putinserver(id)
{
set_bit(g_bit_is_connected, id)
if(is_user_bot(id) || is_user_hltv(id))
{
set_bit(g_bit_immunity, id)
return PLUGIN_CONTINUE
}