You should implement sanity checks on the server to check if exploiters are breaking your tools of any sort, try not to rely on the client way too much to handle your scripts
Personally I’d use the script in ServerScriptService to handle the checks, & check if the player is firing the Event way too much times so that it’s handled on the server
Put the Script in ServerScriptService, it is completely hidden from the client (exploiters and players).
It makes things a bit more tidy since you have one script handing it, and not a script in every tool (messy).
A script in every tool will also create multiple threads, and multiple connections that do the same thing, which I am pretty sure isn’t memory/performance efficient.
That’s true, but even if the script isn’t inside of ServerScriptService, it is still server-sided. Normal Scripts run on the server, and local scripts run on the client. But if the script isn’t in a hidden place, exploiters just know that it’s there, yet they can’t make changes to it.
And as Jackscarlett said, add sanity checks, to make sure nothing inappropriate is abused.
It’s better to keep things server-sided as it is true it can prevent exploiters from exploiting your scripts and game mechanics, but this shouldn’t be the case all the time, if a mechanic/script is just for visual effects and doesn’t require replication to the server then its best to just use local scripts on the client side.
The reason why this works well is because exploiters geninuely don’t have more access to the game other than client access to scripts. All ServerScriptService scripts are transferred to the server and are run by server. The exploiter would need to be doing real hacking to the server to actually access the serverscriptservice as it stands currently there is little to no one in roblox who is able to hack into roblox servers though possible.
EDIT: what @LightningLion58 and @JackscarIitt was trying to say when telling you to do sanity checks, if the requests were legitimate or not, basically you’re checking whether the values of your variables are sensible and/or expected.
For example:
You may decide to make a coin system, out of no where there is a request that user is getting coins every second, maybe 50000. What you can do is set a timer if the user is making requests at a certain speed that would be not possible to do in your game, you can simply kick them or even maybe a limit to the amount coins you can actually get in your game by checking the requested amount. Of course nothing is perfect you will always get exploiters whether you like it or not, and they will ruin your game best thing to is make your game less vulnerable to the ones we can fix.
Yes, doing that from the server is a good idea, otherwise, exploiters can change them.
Exploiters can change anything accessible for them (except for server scripts). But somethings are not too important to do on the server.
I’d say do it on the client, and make sure that from the server, requests from the same player aren’t sent too fast.
Even though exploiters can’t access the server, you need to make sure you don’t overload the server, otherwise you’ll notice latency issues. That’s why some things you should actually do on the client.
Such as GUIs, exploiters can change GUIs, but it wouldn’t help them, so there’s no need to do it from the server.
For example, you can make a player-specific cool down.
Let’s say the reload time is 2 seconds:
So you can add a wait in the client (to prevent remote spam).
And in the server you can filter which players are in the middle of reloading (so prevent them from shooting), and which players can shoot.
local playersWithCooldown = {} --Players that reload
local reloadTime = 2
RemoteEvent.OnServerEvent:Connect(function(plr)
if not table.find(playersWithCooldown, plr.Name) then
--Code logic to shoot.
--Now their bullets are over, so we add them to the table.
table.insert(playersWithCooldown, plr.Name)
wait(reloadTime) --Wait until reload finish
local placeInTheTable = table.find(playersWithCooldown, plr.Name) --Find the player name in the table.
table.remove(table.insert(playersWithCooldown, placeInTheTable) --remove them from the table.
end
end)
This is one way to do so:
I basically add that players that are reloading to the table, and if they are on the table, they can’t shoot.
After 2 seconds, they are removed from the table and can shoot again.
There are many other ways and checks that you can do on different things.