A little history lesson:
In the beginning of Roblox, both the client and server had equal say in modifying a DataModel.
The server could (and still can) do anything, change any property on anything etc.
Local scripts could essentially do the same. If a local script cloned something, changed a stat in a leaderboard etc., then it would inform the server and the server would replicate it for everyone so that a change made by one player’s computer would be seen by all players in a server.
It was kind of beautiful.
The problem with this was that it left the DataModel wide open to unintended/malicious changes - exploits.
The simplest one (which I used to do really often) was changing leaderstats in RPG places with Cheat Engine or similar products.
I could simply change the money value to 999999 and the client would actually replicate this change to the server! I could actually use this money!
There was an answer to this in particular, a kind of an anti-exploit.
Normally, in an RPG for example, you would gain EXP and money stats for killing monsters, lose money from buying weapons etc.
These are known and approved ways to change your stats.
Then, there was a script monitoring the stats.
If the stats changed because you performed one of the approved actions, then that was allowed.
If the stats changed unexpectedly, then they must’ve been changed by an exploit.
When I tried hacking my stats in one of… stravant’s games, I believe?, I got kicked and the game showed a message to EVERYONE that I had exploited! I got 0wned! What an embarrassment!
That was a very benign exploit.
Edgy kids would execute inappropriate scripts and give everyone body parts which cannot be named on the devforum.
Or just loopkill everyone. Or kick them outright. Or generate a billion Messages or GUIs to create lag.
It got really annoying for the players and caused a lot of trouble for the Roblox company because the game was supposed to be appropriate for all ages.
In 2014, Filtering Enabled was introduced.
What this meant is that the server wouldn’t simply listen to every change the client made.
If the client created a new part, cloned something, changed a part’s color… it would show up locally instantly (there is no point in stopping that), but it would not show up for anyone else.
That update also added RemoteEvents and RemoteFunctions. The client/server could Fire these to send a signal to the client/server and run code.
In effect, they allowed bypassing FilteringEnabled in ways that you want to allow in your game.
Your own LocalScript that just copies the tool to the Inventory?
It doesn’t have any effect. It would’ve done something before 2014.
An exploiter doing the same? He can’t do it either.
An exploiter exploding everyone’s heads? Other players’ characters are not his business, so the server ignores his attempt to delete parts.
In order to allow someone to explode someone else’s head, you have to create a RemoteEvent, make a script listen to it that takes another player as an argument and explodes their head, then fire that event from the client with another player as the argument.
By writing such a script, you agree that yes, exploding someone else’s head is an intended part of your game. To explode someone’s head, you must fire this event instead of just deleting the head directly.
Similarly, if there is a tool in ReplicatedStorage, just chilling, should an exploiter be able to just get it instantly without needing to do or pay anything?
No, of course not. And thanks to Filtering Enabled, he can’t.
You have to tell the server: hey, I want to pick up this book. Or buy this book.
The server then gets the signal: this player wants to buy this book. Take some of their money and clone the book into their inventory.
All other online games and online applications are Filtering Enabled!
When you submit a reply on the DevForum, you don’t just will the post into existence with Inspect Element and have it appear for everyone else. That is essentially what a local script that copies a tool into the inventory does. It’s only on your screen and no-one else sees it.
Instead, you send a network request (fire a remote event) with the arguments of: which thread to post the reply in, which post are you replying to, the body/content of the reply.
The server then receives this request and updates the thread with your new post for everyone to see.
There’s a convenient hole in FilteringEnabled, though, and that’s player-owned parts.
The player owns their own character and most unanchored parts near them.
When you move in-game, your character moves instantly and everyone else sees it happen without any RemoteEvents involved. This is because the player owns its character and is allowed to move it without FilteringEnabled stopping it.
This takes some of the load off of the server and makes physics more responsive.
It also means an exploiter can just set its Torso’s Position to teleport anywhere.
A movement anti-exploit is therefore similar to the leaderboard anti-exploit I described above: instead of approving/declining actions that come in through remotes, it has to monitor and veto changes the player makes to its character.
If the player suddenly moves 100 studs in 0.1 seconds, then it must have exploited because you can’t go that fast with 16 WalkSpeed - unless the player had just used a teleporter in the game, which is an approved way to move 100 studs in an instant.
A player that uses a teleporter (in a game with such an anticheat) should fire a remote event saying: hey, I want to use this teleporter. The server will then teleport the player without triggering the anticheat.
Even better: the player should fire a remote event saying: hey, I’m about to use this teleporter, please don’t freak out when I move 100 studs instantly, and then just do it. The server should then verify whether the player was actually close enough to the teleporter to use it and whether the player actually went to the teleporter’s destination. If not, that player must’ve done something really sussy.
My rambling ends here