Building on @goldenstein64 answer, have you considered using a count when implementing sanity checks?
This enables a remove event/function to be called multiple times in a short period of time (e.g. if firing bullets from an automatic weapon) without triggering as many false positives or a lengthy cooldown.
For example:
--Variables
local requestsLimit = 20
local sanityChecks = {}
--Refresh Sanity Checks
coroutine.wrap(function()
while wait(5) do
sanityChecks = {}
end
end)()
--Main
Remote.OnServerEvent:Connect(function(player,...)
--Sanity Checks
local remoteName = Remote.Name
if not sanityChecks[player] then
sanityChecks[player] = {}
end
local requests = sanityChecks[player][remoteName]
if not requests then
requests = 1
sanityChecks[player][remoteName] = requests
else
sanityChecks[player][remoteName] = requests + 1
end
if requests > requestsLimit then
--Warn user is making too many requests
wait(1)
end
--Do your stuff
end)
This code is very well written and seems to get the job done really well. I like the idea of having a coroutine to handle refreshing of the debounces.
However, I would question if itâs a good idea to store the player object themself in the sanity array. Would it not be better to store player.UserId instead?
The only caveat with not using the playerâs UserId is that if the sanity check table doesnât refresh, then a reference to the player will be kept which will prevent their object from being garbage collected should they disconnect from the game. Otherwise, thereâs no real difference between using it or not.
The reason people kick the player is the same reason they ban them; to deter any future exploiting attempts and to remove them from the game. If your game is well thought out and well executed there shouldnât be any incorrect parameters sent from the localscripts.
Manual moderation is different from embedding a kick function into your scripts for a failed sanity check, whether thatâs a developer-made fault or one thatâs generated from spoofed or wrong arguments. Manual moderation is a band-aid solution to âdeter future exploiting attemptsâ which is only relevant to a single account. Itâs not scalable or effective. The proper solution is to fix your game.
I think itâs just as valid as any other vote to kick system since they are both checking for exploiters.
Regardless, Iâm by no means saying that you should always kick people who failed sanity checks (do to false positives) however there are some situations where you can be 100% sure that a player is exploiting, and it requires immediate action. An example of this would be when phantom forces kicks you for fly hacking, or when jailbreak kicks you for no clip: both of these are situations where there is no room for false positives (the game is sure the player is hacking) and kicking the player is actually required. Anyways, I understand now that spoofed or incorrect arguments sent through remotes do not require immediate action or attention, and so ignoring the request instead of punishing the player is the correct choice in that scenario.
Vote kick is also a form of manual moderation, by community instead of by staff.
Kicking players for explicitly exploiting is fair in itself, if thatâs the intended function of your script. Iâm generalising my response towards sanity checks of remotes in general though.
If youâre not explicitly checking for those kinds of exploits with remotes or whatever and itâs simply a remote for client-server communication for some kind of game functionality, thereâs no reason to kick a player - just reject the request or do nothing if the checks fail. If a player does get kicked for hitting a false positive or something thatâs the fault of the developer, thatâs dangerous for UX and it doesnât really help anyone either. A simple request reject allows everyone to continue playing, even in error (not as in a script-terminating error though).
Anyway, that being said, feel free to hit my DMs if youâre interested in further discussion or anything. I think weâve dragged this topic out a bit, lol.
Hey, I know itâs been a year but itâs still a very important topic,
So how I do it is-
-- Server
local RemoteEvent = game.ReplicatedStorage["NAME HERE"]
RemoteEvent.OnServerEvent:Connect(function(client, argument1)
if argument1 == 'ye this is it' then
-- code here
end
end)
-- Client
-- code here
game.ReplicatedStorage['name here']:FireServer('ye this is it')
You have the right idea, but what youâve currently ran into is a password-protected remote which is not real security. It could be a different story if your script actually needed to send a string though and the server needs to either validate or sanitise it.
If youâre validating a string for example and donât want it to exceed a certain number of characters, you can check the length of the string using string.len or the length operator (#). Then after getting the number, check if its under a certain amount. If it is, then proceed with your code. If not, then end it there.
If youâre sanitising a string for example and donât want it to exceed a certain number of characters, you would use string.sub in order to cut off excess, so that the server is only working with the first 200 characters of the string or so. You can then proceed using that sanitised string.
A personal favourite thing of mine with regards to sanity checks is guard clauses, so I can âdetachâ my checks from my code. So rather than an if statement encapsulating all my code, its just a line or some that act on the received arguments.
OnServerEvent:Connect(function (player, a)
if #a > 200 then return end
-- Code here
end)