/*
* CSB Spinbot Detection
* Copyright (C) 2026 counter-strike-boost.com
*
* Samples pev_v_angle each frame and flags spinbot / anti-aim: a yaw that
* rotates faster than a human can move the mouse, or a pitch outside the legal
* -89..89 range, over several sustained frames.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version. It is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See for details.
*/
#include
#include
new const PLUGIN[] = "CSB Spinbot Detection"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
new g_pEnabled, g_pMaxYaw, g_pStrikes, g_pAction
new Float:g_fLastYaw[33]
new bool:g_bHasLast[33]
new g_iStrikes[33]
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_spin_enabled", "1")
g_pMaxYaw = register_cvar("csb_spin_maxyaw", "50.0")
g_pStrikes = register_cvar("csb_spin_strikes", "10")
g_pAction = register_cvar("csb_spin_action", "0")
register_forward(FM_PlayerPreThink, "fwPreThink")
}
public client_putinserver(id)
{
g_bHasLast[id] = false
g_iStrikes[id] = 0
}
public fwPreThink(id)
{
if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id) || is_user_bot(id))
return FMRES_IGNORED
new Float:angles[3]
pev(id, pev_v_angle, angles)
new bool:bad = false
new reason[24]
// legal pitch is clamped to [-89, 89]; anything beyond is a hack angle
if (angles[0] > 89.5 || angles[0] < -89.5)
{
bad = true
copy(reason, charsmax(reason), "illegal pitch")
}
else if (g_bHasLast[id])
{
new Float:delta = angles[1] - g_fLastYaw[id]
// normalise to the shortest signed turn
while (delta > 180.0) delta -= 360.0
while (delta < -180.0) delta += 360.0
if (delta < 0.0)
delta = -delta
if (delta > get_pcvar_float(g_pMaxYaw))
{
bad = true
copy(reason, charsmax(reason), "impossible yaw speed")
}
}
g_fLastYaw[id] = angles[1]
g_bHasLast[id] = true
if (bad)
{
g_iStrikes[id]++
if (g_iStrikes[id] >= get_pcvar_num(g_pStrikes))
{
flag(id, reason)
g_iStrikes[id] = 0
}
}
else if (g_iStrikes[id] > 0)
{
g_iStrikes[id]--
}
return FMRES_IGNORED
}
flag(id, const reason[])
{
new name[32], authid[35]
get_user_name(id, name, charsmax(name))
get_user_authid(id, authid, charsmax(authid))
log_amx("[CSB Spinbot] %s <%s> flagged: %s", name, authid, reason)
if (get_pcvar_num(g_pAction) == 1)
{
server_cmd("kick #%d ^"CSB: spinbot / anti-aim detected^"", get_user_userid(id))
server_exec()
}
else
{
client_print(0, print_chat, "[CSB] %s is suspected of using spinbot / anti-aim (%s).", name, reason)
}
}