options: prefix: &e[&cAAAC&e] punish: true # Should the players get kicked? max-vl: 5 # The amount of times that the player can fail the checks before getting kicked # AAAC 1.0 BY pingwinek#9268, usage of any code in this project for any use wheter commercial or non commercial is permitted if given credit. # NOTE, aaac (AdvancedAntiAutoClicker) will NOT ban anyone, it will just send notifications to admins. # The purpose here is to detect autoclickers over a long period of time, dont expect it to detect autoclickers when a fight lasts 2 seconds okay? # It's meant to detect closet cheating on practice/pvp servers, not on your aternos survival server. It's also the (first?) anti autoclicker made in skript to utilize concepts used in modern anticheats like deviation, consistency or kurtosis. (And actually utilizing those at least semi-properly) # Additionaly, nothing here is skidded, i spent a long time coding everything myself, the methods used to detect autoclicking are known to almost everyone and used in a variety of anticheats, this is a proof of concept. # Current checks include: # Autoclicker # (A) Limit - A hard cps limit (WARNING, BASED ON ARM SWING EVENT) # (B) Blatant - Little to no difference between cps values # (C) Deviation - Average deviation in a list of differences between cps values # (D) Rounded - Rounded max and min values from a list of differences # (E) Difference - Experimental check, similar to the rounded check # (F) Kurtosis - Basic kurtosis algorithm # (G) Frequency - Checks for repeated rounded cps values # (H) Range - Deviation but improved a bit # (I) Pattern - Quick pattern comparison check # Permissions: # aaac.notify - any person having this permission can viev alerts and toggle them on/off # CAUTION! DEV OPTIONS. # Do not touch these values unless you have taken a look at the code and understand what they're doing. # I already configured them to not false flag, but if you do find them less than ideal, feel free to experiment a bit. armswing-limit: 31 armswing-buffer: 16 min-cps: 6.1 difference-min: 0.14 difference-buffer: 8 deviation-min: 0.29 deviation-buffer: 2 kurtosis-max: 0.44 range-limit: 0.33 version: 1.2 # DO NOT CHANGE on load: wait 2.5 seconds set {_version} to text from "http://site21231.web1.titanaxe.com/api.php" if "{@version}" is not "%{_version}%": send "{@prefix} &fAn update is available!" to console send "{@prefix} &fDownload at: https://forums.skunity.com/resources/aaac-advancedantiautoclicker.1573/" to console else: send "{@prefix} &fYou are running the lastest version of AAAC (%{_version}%)" to console function alert(p: player, check: text, moreinfo: text="null"): add 1 to {aaac::flags::%{_p}%} if {aaac::flags::%{_p}%} > {@max-vl}: if {@punish} = true: kick {_p} due to "{@prefix} &fAutoclicking is not allowed!" delete {aaac::flags::%{_p}%} loop all players: check [loop-player has permission "aaac.notify"]->[{aaac::alerts::%loop-player%} = true] if {_moreinfo} != "null": send formatted "{@prefix} &f%{_p}% failed &c%{_check}%" to loop-player else: send formatted "{@prefix} &f%{_p}% failed &c%{_check}%" to loop-player command /alerts: permission: aaac.notify permission message: {@prefix} &cYou don't have the permission required to use this command. trigger: if {aaac::alerts::%player%} = false: set {aaac::alerts::%player%} to true send "{@prefix} &fAlerts enabled" stop if {aaac::alerts::%player%} = true: set {aaac::alerts::%player%} to false send "{@prefix} &fAlerts disabled" stop if {aaac::alerts::%player%} is not set: set {aaac::alerts::%player%} to true send "{@prefix} &fAlerts enabled" stop on left click: # ON LEFT CLICK SUPREMACY!!!11!! if {aaac::cps::%player%} > {@min-cps}: if size of {aaac::cps::list::%player%::*} = 10: if size of {aaac::patterns::%player%::*} > 4: delete {aaac::patterns::%player%::*} if {aaac::patterns::%player%::*} contains "%{aaac::cps::list::%player%::*}%": alert(player, "Autoclicker I &f(Pattern)", "Pattern: %{aaac::cps::list::%player%::*}%") # Pattern comparison (This check is ASS, do not skid it.) else: add "%{aaac::cps::list::%player%::*}%" to {aaac::patterns::%player%::*} set {aaac::cps::average::%player%} to sum({aaac::cps::list::%player%::*}) / 10 add difference between {aaac::cps::average::%player%} and {aaac::previous::cps::average::%player%} to {aaac::difference::list::%player%::*} add difference between {aaac::cps::average::%player%} and {aaac::previous::cps::average::%player%} to {aaac::comparison::list::%player%::*} if size of {aaac::comparison::list::%player%::*} >= 5: loop {aaac::comparison::list::%player%::*}: set {_squared} to (loop-value - {_mean})^2 set {_sum} to {_sum} + {_squared} set {_stddev} to sqrt({_sum} / 8) if {_stddev} < {@range-limit}: add 1 to {aaac::range::flag::%player%} if {aaac::range::flag::%player%} > 2: delete {aaac::range::flag::%player%} alert(player, "Autoclicker H &f(Range)", "Difference: %{_stddev}%") # Improved deviation check set {_diff} to difference between min({aaac::comparison::list::%player%::*}) and max({aaac::comparison::list::%player%::*}) if "%{_diff}%" does not contain ".": add 1 to {aaac::rounded::flag::%player%} if {aaac::rounded::flag::%player%} >= 3: delete {aaac::rounded::flag::%player%} alert(player, "Autoclicker D &f(Rounded)", "Difference: %{_diff}%") # Detects ass randomization set {_diff::experimental} to rounded down max({aaac::comparison::list::%player%::*}) - rounded down min({aaac::comparison::list::%player%::*}) if {_diff::experimental} = 0: add 1 to {aaac::difference::flag::%player%} if {aaac::difference::flag::%player%} >= 3: alert(player, "Autoclicker E &f(Difference)") # Difference between min and max but rounded, yay. delete {aaac::difference::flag::%player%} else: if {aaac::difference::flag::%player%} > 0: remove 1 from {aaac::difference::flag::%player%} delete {aaac::comparison::list::%player%::*} if size of {aaac::difference::list::%player%::*} >= 8: set {_mean} to sum({aaac::difference::list::%player%::*}) / 8 loop {aaac::difference::list::%player%::*}: set {_squared} to (loop-value - {_mean})^2 set {_sum} to {_sum} + {_squared} set {_stddev} to sqrt({_sum} / 8) if {_stddev} < {@deviation-min}: add 1 to {aaac::deviation::flag::%player%} if {aaac::deviation::flag::%player%} >= {@deviation-buffer}: alert(player, "Autoclicker C &f(Deviation)", "Deviation: %{_stddev}%") # Deviation, that's it, deviation. I mean average deviation. else: if {aaac::deviation::flag::%player%} > 0: remove 1 from {aaac::deviation::flag::%player%} loop {aaac::difference::list::%player%::*}: add ((loop-value - {_mean}) / {_stddev})^4 to {_kurtosis} set {_kurtosis} to {_kurtosis} * size of {aaac::difference::list::%player%::*} * (size of {aaac::difference::list::%player%::*} + 1) / ((size of {aaac::difference::list::%player%::*} - 1) * (size of {aaac::difference::list::%player%::*} - 2) * (size of {aaac::difference::list::%player%::*} - 3)) - 3 * (size of {aaac::difference::list::%player%::*} - 1)^2 / ((size of {aaac::difference::list::%player%::*} - 2) * (size of {aaac::difference::list::%player%::*} - 3)) if {_kurtosis} < {@kurtosis-max}: alert(player, "Autoclicker F &f(Kurtosis)", "Kurtosis result: %{_kurtosis}%") # Kurtosis (veri cool). delete {aaac::difference::list::%player%::*} if difference between {aaac::cps::average::%player%} and {aaac::previous::cps::average::%player%} < {@difference-min}: add 1 to {aaac::difference::flag::%player%} if {aaac::difference::flag::%player%} >= {@difference-buffer}: alert(player, "Autoclicker B &f(Blatant)", "Difference: %difference between {aaac::cps::average::%player%} and {aaac::previous::cps::average::%player%}%") # Very basic, meant to detect impossible/too small difference when clicking, hence why its called blatant else: if {aaac::difference::flag::%player%} > 0: remove 1 from {aaac::difference::flag::%player%} set {aaac::previous::cps::average::%player%} to {aaac::cps::average::%player%} delete {aaac::cps::average::%player%} add {aaac::cps::%player%} to {aaac::cps::list::%player%::*} if size of {aaac::cps::list::%player%::*} >= 15: loop {aaac::cps::list::%player%::*}: add 1 to {_frequency::%rounded down loop-value%} set {_flagged} to false delete {aaac::cps::list::%player%::*} loop 25 times: if {_frequency::%loop-value%} >= 12: add 1 to {aaac::frequency::flag::%player%} if {aaac::frequency::flag::%player%} >= 3: alert(player, "Autoclicker G &f(Frequency)", "Frequency: %{_frequency::%loop-value%}%/15") # This check detects small randomization over 1-2 cps. delete {aaac::frequency::flag::%player%} set {_flagged} to true stop loop if {_flagged} = false: if {aaac::frequency::flag::%player%} > 0: remove 1 from {aaac::frequency::flag::%player%} add 1 to {aaac::cps::%player%} wait 1 second remove 1 from {aaac::cps::%player%} on arm swing: # Worse than on left click, i made sure to only use it for a limit check. if {aaac::armswings::%player%} > {@armswing-limit}: add 1 to {aaac::limit::flag::%player%} if {aaac::limit::flag::%player%} > {@armswing-buffer}: alert(player, "Autoclicker A &f(Limit)", "Swings: %{aaac::armswings::%player%}%%nl%Limit: {@armswing-limit}") # Limit check, basic, simple, yay. delete {aaac::limit::flag::%player%} else: if {aaac::limit::flag::%player%} > 0: remove 1 from {aaac::limit::flag::%player%} add 1 to {aaac::armswings::%player%} wait 1 second remove 1 from {aaac::armswings::%player%} on join: set {aaac::cps::%player%} to 0 set {aaac::armswings::%player%} to 0 set {aaac::flags::%player%} to 0 on quit: # No leaving variables/lists behind to avoid performance/skript issues # Deletion of main variables delete {aaac::cps::%player%} delete {aaac::armswings::%player%} delete {aaac::flags::%player%} # Deletion of lists delete {aaac::cps::list::%player%::*} delete {aaac::comparison::list::%player%::*} delete {aaac::difference::list::%player%::*} delete {aaac::patterns::%player%::*} # Deletion of buffers delete {aaac::limit::flag::%player%} delete {aaac::frequency::flag::%player%} delete {aaac::difference::flag::%player%} delete {aaac::deviation::flag::%player%} delete {aaac::rounded::flag::%player%} delete {aaac::range::flag::%player%} # Deletion of various other variables delete {aaac::cps::average::%player%} delete {aaac::previous::cps::average::%player%}