How could I improve my Anti-Cheat?

Hello. I have made a server sided Anti-Cheat script.

This script blocks:

  • MultiTooling,

  • FE-GodMode(Humanoid Deletion),

  • Inappropriate animation(A balloon animation which exploiters can use in a NSFW context),

  • Paranoid(Deleting humanoid root part joint. Stops FE invisibility and other exploits),

  • StrafingNoPhysics(Stops some noclipping exploits, exploiters can still use other methods to noclip),

  • InvalidMeshDeletion(Stops deletion of hat meshes NOT IMPLEMENTED YET)

So the anti-cheat basically functions as Filtering Enabled but fixes some stuff FE does not.

So basically how could I improve the Anti-Cheat script?

  • Are there any specific improvements I could make to this script?
  • Are there any bugs in it?
  • Any general improvements?
  • And what else should I add to my script and what other exploits should I patch?

Also, would you use this script on your game?

Would you use this script in your game?
  • Yes
  • No (Respond with a reason)

0 voters

local Players = game:GetService("Players")

local function ProtectHat(Hat)
	local Handle = Hat:WaitForChild("Handle", 20)

	if Handle:IsA("Part") and Handle:FindFirstChildOfClass("SpecialMesh") then
		-- // UNFINHISHED
	end
end

local function KillHumanoid(Humanoid)
	if Humanoid then
		Humanoid.Health = 0
		Humanoid:ChangeState(Enum.HumanoidStateType.Dead)
		if Humanoid.BreakJointsOnDeath then
			Humanoid:BreakJoints()
		end
	end
end

Players.PlayerAdded:Connect(function(Plr)
	Plr.CharacterAdded:Connect(function(Character)
		for _, v in ipairs(Character:GetChildren()) do
			if v:IsA("Accoutrement") then
				coroutine.wrap(ProtectHat)(v)
			end
		end

		Character.ChildAdded:Connect(function(Child)
			if Child:IsA("Accoutrement") then
				ProtectHat(Child)
			elseif Child:IsA("BackpackItem") then
				local Count = 0

				task.wait()

				for _, v in ipairs(Character:GetChildren()) do
					if v:IsA("Tool") then
						Count += 1
						if Count > 1 then
							v.Parent = Plr:FindFirstChildOfClass("Backpack") or Instance.new("Backpack", Plr)
						end
					end
				end
			end
		end)


		local Humanoid = Character:FindFirstChildOfClass("Humanoid") or Character:WaitForChild("Humanoid")

		Humanoid.AncestryChanged:Connect(function(Child, Parent)
			if Child == Humanoid and Character and (not Parent or not Character:IsAncestorOf(Humanoid)) then
				Humanoid.Parent = Character
			end
		end)

		Humanoid.StateChanged:Connect(function(Last, State)
			if Last == Enum.HumanoidStateType.Dead and State ~= Enum.HumanoidStateType.Dead then
				KillHumanoid(Humanoid)
			elseif State == Enum.HumanoidStateType.StrafingNoPhysics then
				KillHumanoid(Humanoid)
			end
		end)


		local Animator = Humanoid:WaitForChild("Animator")

		Animator.AnimationPlayed:Connect(function(Track)
			local AnimationId = Track.Animation.AnimationId
			if AnimationId == "rbxassetid://148840371" or string.match(AnimationId, "[%d%l]+://[/%w%p%?=%-_%$&'%*%+%%]*148840371/*") then
				KillHumanoid(Humanoid)
			end
		end)


		local RootJoint = Humanoid.RigType == Enum.HumanoidRigType.R15 and Character:WaitForChild("LowerTorso"):WaitForChild("Root") or Humanoid.RigType == Enum.HumanoidRigType.R6 and Character:WaitForChild("HumanoidRootPart"):WaitForChild("RootJoint")

		local Connection
		Connection = RootJoint.AncestryChanged:Connect(function(_, Parent)
			if not Connection.Connected or Parent then
				return
			end

			Connection:Disconnect()

			if Humanoid then
				KillHumanoid(Humanoid)
			end
		end)
	end)
end)
13 Likes

For animations the players could use the deprecated version of animations, Humanoid:LoadAnimation(). I am unsure if this fires the Animator event. There is a similar event for the humanoid, as well. Maybe add that to prevent animations the deprecated way.

1 Like

This indeed does fire the animation event, I have tested this with the inappropriate animation and it indeed did detect it. But thanks for feedback. :smiley:

1 Like

don’t parent the instance like that

EDIT: fixed grammar

1 Like

It only applies if you assign properties. If you don’t set properties they don’t provide any negative effects.

1 Like

I guess, but it is still good practice if you don’t do that

1 Like

Thank you everyone for your feedback. :grinning:

I have made improvements to my anti-cheat based on your feedback and I will also patch more exploits with it.

This is 100% on the client, the exploiter can disable the script as long as it’s on the client

I’m not too good with anti-cheat by any means but what sussy said is true if your anti-cheat here is on the client only then it doesn’t matter at all unless it’s a noob exploiter, That being said I’ve seen people do server checks and back and fourth somehow to check when scripts are removed etc so that’s a good idea if you can figure out how.

Umm. This is not correct. The anti-cheat is fully server sided and works by security by design.

But anyways this thread is solved so please do not respond to it. Thank you. :slight_smile:

do u mind if i use this script for my game??///??

Well sure. However the version I uploaded is broken.
Here is a newer version which works:

local Players = game:GetService("Players")

-- // If your game has admin commands which require noclipping, set this to false.
local preventStrafingNoPhysics = true



-- // Do not touch the code below unless you known what you are doing!

local function protectHat(hat)
	local handle = hat:WaitForChild("Handle", 30)

	if handle then
		task.defer(function()
			local joint = handle:WaitForChild("AccessoryWeld")

			local connection
			connection = joint.AncestryChanged:Connect(function(_, parent)
				if not connection.Connected or parent then
					return
				end

				connection:Disconnect()

				if handle and handle:CanSetNetworkOwnership() then
					handle:SetNetworkOwner(nil)
				end
			end)
		end)

		if handle:IsA("Part") then
			local mesh = handle:FindFirstChildOfClass("SpecialMesh") or handle:WaitForChild("Mesh")

			mesh.AncestryChanged:Connect(function(child, parent)
				task.defer(function()
					if child == mesh and handle and (not parent or not handle:IsAncestorOf(mesh)) then
						mesh.Parent = handle
					end
				end)
			end)
		end
	end
end

local function killHumanoid(humanoid)
	if humanoid then
		humanoid:ChangeState(Enum.HumanoidStateType.Dead)
		humanoid.Health = 0
	end
end

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		for _, v in ipairs(character:GetChildren()) do
			if v:IsA("Accoutrement") then
				coroutine.wrap(protectHat)(v)
			end
		end

		character.ChildAdded:Connect(function(child)
			if child:IsA("Accoutrement") then
				protectHat(child)
			elseif child:IsA("BackpackItem") then
				local count = 0

				task.defer(function()
					for _, v in ipairs(character:GetChildren()) do
						if v:IsA("Tool") then
							count += 1
							if count > 1 then
								v.Parent = player:FindFirstChildOfClass("Backpack") or Instance.new("Backpack", player)
							end
						end
					end
				end)
			end
		end)


		local humanoid = character:FindFirstChildOfClass("Humanoid") or character:WaitForChild("Humanoid")

		humanoid.AncestryChanged:Connect(function(child, parent)
			task.defer(function()
				if child == humanoid and character and (not parent or not character:IsAncestorOf(humanoid)) then
					humanoid.Parent = character
				end
			end)
		end)

		humanoid.StateChanged:Connect(function(last, state)
			if last == Enum.HumanoidStateType.Dead and state ~= Enum.HumanoidStateType.Dead then
				killHumanoid(humanoid)
			elseif preventStrafingNoPhysics and state == Enum.HumanoidStateType.StrafingNoPhysics then
				killHumanoid(humanoid)
			end
		end)

		do
			local connection

			connection = humanoid.Died:Connect(function()
				if not connection.Connected then
					return
				end

				connection:Disconnect()

				task.wait(Players.RespawnTime + 1.5)

				if workspace:IsAncestorOf(humanoid) then
					player:LoadCharacter()
				end
			end)
		end

		local animator = humanoid:WaitForChild("Animator")

		animator.AnimationPlayed:Connect(function(animationTrack)
			local animationId = animationTrack.Animation.AnimationId
			if animationId == "rbxassetid://148840371" or string.match(animationId, "[%d%l]+://[/%w%p%?=%-_%$&'%*%+%%]*148840371/*") then
				killHumanoid(humanoid)
			end
		end)


		local connections = {}
		local function makeConnection(Conn)
			local connection
			connection = Conn:Connect(function(_, parent)
				if not connection.Connected or parent then
					return
				end

				for _, v in ipairs(connections) do
					v:Disconnect()
				end

				if humanoid then
					killHumanoid(humanoid)
				end
			end)

			table.insert(connections, connection)
		end

		local rootJoint = humanoid.RigType == Enum.HumanoidRigType.R15 and character:WaitForChild("LowerTorso"):WaitForChild("Root") or humanoid.RigType == Enum.HumanoidRigType.R6 and character:WaitForChild("HumanoidRootPart"):WaitForChild("RootJoint")

		makeConnection(rootJoint.AncestryChanged)

		if humanoid.RigType == Enum.HumanoidRigType.R15 then
			makeConnection(character:WaitForChild("UpperTorso"):WaitForChild("Waist").AncestryChanged)
		end
	end)
end)

Anyways I will probably upload this to #resources as many people would like to use it.

4 Likes

thank you so much dude and where did you learn scripting

1 Like

I learned scripting from: devforum, youtube, free models, roblox dev wiki, github, and from developing games.

2 Likes