Due to the replies made telling me to fix this code, after 2 years here I come!
I am introducing a short module named “Protector” that will help you protect your ClickDetectors and ProximityPrompts from exploiters.
First of all, what are the issues with ClickDetectors and ProximityPrompts?
-
Roblox doesn’t seem to make distance checks for ClickDetectors, allowing exploiters to extend the
MaxActivationDistance
on the client and trigger them from anywhere on the map. (Or with an executor they can just trigger it) -
Roblox doesn’t seem to check if the ProximityPrompt is enabled or not. If you disable a ProximityPrompt in your game expecting no players to interact with an object, exploiters will still be able to trigger that ProximityPrompt. (They seem to do some sort of distance check for ProximityPrompts this is why I didn’t added it in the module, though the range is kinda high)
How does this module work?
This module returns a table with a function named getSafeInput(Instance)
. You pass a ClickDetector/ProximityPrompt and it will return to you another table containing an event named Triggered
which is the event you will connect to in order to receive safe input.
Can you show me an example of how I would set up my code?
Have in mind that the Triggered
event will trigger for both RightClick (false)
/ LeftClick (true)
for ClickDetectors.
local protector = require(game.ServerStorage.Protector)
local Input1 = protector.getSafeInput(workspace.Part1.ClickDetector)
Input1.Triggered:Connect(function(Player, IsLeftClick)
print(Player, IsLeftClick)
end)
local Input2 = protector.getSafeInput(workspace.Part2.ProximityPrompt)
Input2.Triggered:Connect(function(Player)
print(Player)
end)
Module Link: Protector
Source Code:
--{- ⚜️ Main Objects ⚜️ -}--
local function IsPlayerAlive(Player) --> Determines if the player is alive depending on the Humanoid, HumanoidRootPart, and Health.
local Character = Player.Character
if Character and Character.Parent == workspace then
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local HumanoidRootPart = Character.PrimaryPart
if Humanoid and Humanoid.Health > 0 and HumanoidRootPart then
return true
end
end
return false
end
local function GetBoundingBox(Object) --> Returns the CFrame and Size of Model/BasePart.
if Object:IsA("BasePart") then
return Object.CFrame, Object.Size
elseif Object:IsA("Model") then
return Object:GetBoundingBox()
end
end
local function IsSafe(Player, InputObject) --> Determines if the ClickDetector/ProximityPrompt can be activated.
if IsPlayerAlive(Player) then
if InputObject:IsA("ClickDetector") then
local ObjectCFrame, ObjectSize = GetBoundingBox(InputObject.Parent)
local Position, Size = ObjectCFrame:PointToObjectSpace(Player.Character.PrimaryPart.Position), ObjectSize/2 + Vector3.one*InputObject.MaxActivationDistance
return math.abs(Position.X) <= Size.X and math.abs(Position.Y) <= Size.Y and math.abs(Position.Z) <= Size.Z
else --> Assumes is a ProximityPrompt
return InputObject.Enabled --> We don't check for distance because Roblox already does it, though their check is kinda big.
end
end
return false
end
--{- 🌐 Main Table 🌐 -}--
local protector = {}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------||
---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]--- 🧾 Script Start 🧾 ---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---[]---
---> 📚 ClickProtector Library 📚 <---
function protector.getSafeInput(InputObject) --> Returns a table with a Triggered event that you can connect to.
local Triggered = Instance.new("BindableEvent")
local Input = {}
Input.Triggered = Triggered.Event
local ObjectType = (typeof(InputObject) == "Instance" and InputObject.ClassName or typeof(InputObject))
if ObjectType == "ClickDetector" then
InputObject.MouseClick:Connect(function(Player)
if IsSafe(Player, InputObject) then
Triggered:Fire(Player, true) --> Left Click
end
end)
InputObject.RightMouseClick:Connect(function(Player)
if IsSafe(Player, InputObject) then
Triggered:Fire(Player, false) --> Right Click
end
end)
elseif ObjectType == "ProximityPrompt" then
InputObject.Triggered:Connect(function(Player)
if IsSafe(Player, InputObject) then
Triggered:Fire(Player)
end
end)
else
error("invalid argument #1 to 'protector.getSafeInput' (ClickDetector or ProximityPrompt expected, got "..ObjectType..")", 2)
end
return Input
end
return protector --> By focasds :)
Thanks for using this module! (If you are not a fan of emojis in the code, you can remove them, I love to separate my code by comments and emojis)