To simply explain this is an inappropriate cheat which shows players characters playing an inappropriate animation (taking their hand and you know what).
This is the situation; one of our moderators recently got banned from our experience after running this script with their exploit software, it’s an understatement to say that we’re heartbroken and furious about this.
Not to forget mentioning that they’ve recorded themselves while doing this with a “friend”.
Actions have consequences, and we demoted this individual as soon as we could.
Then we came to the conclusion that blocking this is necessary, a bunch of minors play our experience every day and we do not tolerate this being shown to them.
How does it work?
It simply works by checking if the animation the player is playing matches animations used in this cheat. Since their “cheat” works by playing a Roblox animation then looping it at a time range where the hand is close to the legs.
This entire resource is basically a “signature” based approach, the code makes sure the animation playing actually sort of matches the blacklisted parameters (e.g. speed, start time).
Then there is the whole "confidence"
concept, which makes sure the animation is actually being looped in that bad time-position, this significantly decreases false-positives to the point where it’s really rare to get one.
You can implement your punishment logic when there is a detection within the onDetection()
function, the default behavior is kicking the player.
Usage
It’s pretty basic, and fully serversided.
Since animations played on the client replicate to the server.
-
Make a script in “ServerScriptService” and name it whatever you want.
-
Then paste the script inside there and test for false-positives, increment
CONFIDENCE_LIMITER
at line 31 if you are experiencing false-positives. -
- big values (eg. 300) causes it too take too long to detect.
-
- low values (eg. 50) may cause false-positives.
- Do not edit the
R6_ANIM*_BLACKLISTED_..
andR15_BLACKLISTED_..
constants. These are fine-tuned to the cheat’s parameters.
This script both detects the R15 and the R6 version of the cheat, though the R6 detection is a bit finicky as the R6 version of the cheat just spams two animations at rapid succession.
--# Author: SyntaxMenace #--
--[[
This script attempts to stop an animation exploit which is labeled "j**king"
It has gone through testing but please test this in your own place yourself
if your game has any of the following animations that are played on characters:
rbxassetid://698251653 => Bug Net - R15 Swing
rbxassetid://72042024 => R6, RapidSlash
rbxassetid://168268306 => R6, Space_Sword_Swing_1
Lag or unpredictable environment factors might cause minor differences in timing and risk false positives.
Though this is shouldn't occur as long as "CONFIDENCE_LIMITER" constant is above 100.
"I applaud the simplicity of this approach because It does exactly
what it’s designed to do for a known exploit: it zeroes in on specific
suspicious animations that no normal player should be running." - ChatGPT o1
]]
-- Update 1/20/2024: Fixed a memory leak.
local Players = game:GetService("Players")
local R15_BLACKLISTED_START_TIME = 0.579 --> Don't change this.
local R15_BLACKLISTED_END_TIME = 0.72 --> Don't change this.
local R6_ANIM1_BLACKLISTED_START_TIME = 0.5 --> Don't change this.
local R6_ANIM2_BLACKLISTED_START_TIME = 1.0 --> Don't change this.
local CONFIDENCE_LIMITER = 150 --> This value should NEVER go below 100
-- limits how many iterations it will take to make sure this animation is being played.
CONFIDENCE_LIMITER = math.max(CONFIDENCE_LIMITER, 100)
CONFIDENCE_LIMITER = math.min(CONFIDENCE_LIMITER, 300)
local function onDetected(Player: Player)
--// Basically your punishment logic here
--// I highly recommend a BanWave logic, but quickly banning or kicking also works.
Player:Kick("You've been kicked for doing the no-no!") -- "You've been kicked for jorking!"
end
local function addToDetectionLoop_R15(player: Player, animationTrack: AnimationTrack)
local timePositions = {}
local confidence = 0
while animationTrack.IsPlaying and confidence <= CONFIDENCE_LIMITER do
task.wait(1 / 24)
local currentTimePos = animationTrack.TimePosition
if not table.find(timePositions, currentTimePos) then
table.insert(timePositions, currentTimePos)
end
confidence += 1
end
--// Handle the case where animation ended before we are confident enough to give a detection.
if confidence < CONFIDENCE_LIMITER then
return "Animation ended too soon."
end
table.sort(timePositions)
if not timePositions[1] or not timePositions[#timePositions] then
return "Time positions are corrupt!" --// might be an edge case, not taking the risk of errors.
end
local suspiciousStartTime = math.abs(timePositions[1] - R15_BLACKLISTED_START_TIME) < 0.05
local suspiciousEndTime = math.abs(timePositions[#timePositions] - R15_BLACKLISTED_END_TIME) < 0.1
-- print( math.abs(timePositions[1] - R15_BLACKLISTED_START_TIME) )
-- print( math.abs(timePositions[#timePositions] - R15_BLACKLISTED_END_TIME), timePositions[#timePositions] )
if suspiciousStartTime and suspiciousEndTime then
onDetected(player)
end
end
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local Humanoid = character:WaitForChild("Humanoid", 15) :: Humanoid
if not Humanoid then return end
local r6_animations = {
countAnimation1 = 0,
countAnimation2 = 0
}
local animationConnection
animationConnection = Humanoid.AnimationPlayed:Connect(function(animationTrack)
local animationId = animationTrack.Animation.AnimationId
local startTime = animationTrack.TimePosition
if animationId == "rbxassetid://698251653" then
--// The r15 version of this cheat works by constantly playing the animation in a bad time-frame.
-- 0.5799 .. 0.6800
-- warn("Playing the suspicious animation")
if math.abs(startTime - R15_BLACKLISTED_START_TIME) > 0.05 then
return "Did not start at blacklisted time-frame."
elseif math.abs(animationTrack.Speed - 0.4) > 0.001 then
return "Either this animation is not the one we're looking for, or the cheat was updated."
end
addToDetectionLoop_R15(player, animationTrack)
elseif animationId == "rbxassetid://72042024" or animationId == "rbxassetid://168268306" then
--// The r6 version of this cheat works by constantly playing two animations in rapid succession.
-- Guard clauses for animations that don't have the blacklisted start times.
if animationId == "rbxassetid://72042024" and math.abs(startTime - R6_ANIM1_BLACKLISTED_START_TIME) > 0.1 then
return "Animation1 did not start at blacklisted frame-time.", startTime
elseif animationId == "rbxassetid://168268306" and math.abs(startTime - R6_ANIM2_BLACKLISTED_START_TIME) > 0.1 then
return "Animation2 did not start at blacklisted frame-time.", startTime
elseif animationTrack.Speed ~= 1 then
return "Animation is either not the animation we're looking for, or the cheat was updated."
end
if animationId == "rbxassetid://72042024" then
r6_animations.countAnimation1 += 1
elseif animationId == "rbxassetid://168268306" then
r6_animations.countAnimation2 += 1
end
local confident_Animation1IsPlaying = r6_animations.countAnimation1 >= CONFIDENCE_LIMITER / 5
local confident_Animation2IsPlaying = r6_animations.countAnimation2 >= CONFIDENCE_LIMITER / 3
if confident_Animation1IsPlaying and confident_Animation2IsPlaying then
animationConnection:Disconnect()
onDetected(player)
else
--// Debugging, uncomment if you're expanding this script and want to test.
-- warn("Animation1 Count", r6_animations.countAnimation1, "confident animation1 is playing rapidly:", confident_Animation1IsPlaying)
-- warn("Animation2 Count", r6_animations.countAnimation2, "confident animation2 is playing rapidly:", confident_Animation2IsPlaying)
end
end
end)
-- This is probably not the best way but eh, I got lazy
-- wont cause performance issues anyway soo
while task.wait(60 + CONFIDENCE_LIMITER / 10) and character:IsDescendantOf(game) do
r6_animations.countAnimation1 = 0
r6_animations.countAnimation2 = 0
end
end)
end)
If you wanted to do this in the client you could just check if player owns a tool with no children, then checking if the tool’s name is whatever this tool is named.
But devforum members will instantly flock to your post saying that “client detections can be bypassed in 0.000000000000000001 nanoseconds” like mosquitoes being attracted by the brightest power of light in the universe. Without realizing one simply does not just have one layer of anti-cheat.