I’ve always been one to heavily lock down my remotes on the server to prevent cheating. The only issue is my checks start to get long and almost redundant, so I’ve tried to keep it to what I need. Even then, if you had a remote where one of the parameters is a part then you’d have your checks base off of thinking it is a part instance. But, if a cheater passes in another instance, the script would have a high change of erroring. Even though it still wouldn’t allow cheaters to do anything, that still annoys me.
So, in my quest to shorten and simplify the process of making server-side checks, I’ve done some research into ways to make it much cleaner. I still have some questions though. Side note: Appologies for any typos or grammar mistakes; I typed this up pretty quickly.
CollectionService Checks
I’ve done some testing with how CollectionService works across the server and client. I can confirm that checks added by the server to an instance cannot in any way be changed by the client. Here is the test I conducted:
I created a part with a server added CollectionService tag to it to see if the client could pass it into a remote and somehow modify the tags it has, even if the part was created in the client.
Server-side code:
local CollectionService = game:GetService("CollectionService")
CollectionService:AddTag(workspace.Part, "Test")
game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player, part)
print(CollectionService:GetTags(part))
end)
Client-side code:
local CollectionService = game:GetService("CollectionService")
wait(5)
print("sending real part")
game.ReplicatedStorage.RemoteEvent:FireServer(workspace.Part)
wait(5)
print("sending fake part")
local part = Instance.new("Part", workspace)
CollectionService:AddTag(part, "Test")
game.ReplicatedStorage.RemoteEvent:FireServer(part)
wait(5)
print("sending modified real part")
CollectionService:AddTag(workspace.Part, "Totally Real Tag")
game.ReplicatedStorage.RemoteEvent:FireServer(workspace.Part)
wait(5)
print("sending another modified real part")
CollectionService:RemoveTag(workspace.Part, "Test")
game.ReplicatedStorage.RemoteEvent:FireServer(workspace.Part)
Output:
sending real part
{
[1] = "Test"
}
sending fake part
{}
sending modified real part
{
[1] = "Test"
}
sending another modified real part
{
[1] = "Test"
}
It’s clear to see here that clients can’t change anything with instance tags. Supposedly, if something that you were planning to check on the server has a CollectionService tag that will always be there then you can check to see if it’s there to fully verify that the instance is valid (this doesn’t mean there would be a tag on everything in the game). So, is this a good way of verifying what the client passed in?
PCall Checks
At the beginning of the post, I talked about how it was annoying that a cheater could cause the server code to error. So, I have supposedly came up with a system that could solve that, in combination with an organized way of managing server-side checks.
Server-side code:
function DoServerCheck(checks)
local checksPassed = false
local success = pcall(function()
checksPassed = checks()
end)
return success and checksPassed
end
game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player, part)
local remoteValid = DoServerCheck(function()
local checksToPass = 1
local checksPassed = 0
if part.Color == Color3.new(1, 0, 0) and part.Name == "RedPart" then
checksPassed += 1
end
return checksToPass <= checksPassed
end)
print(remoteValid)
end)
Client-side code:
wait(5)
print("sending real part")
game.ReplicatedStorage.RemoteEvent:FireServer(workspace.RedPart)
wait(5)
print("sending fake part that doesnt meet the conditions")
game.ReplicatedStorage.RemoteEvent:FireServer(workspace.GreenPart)
wait(5)
print("sending something that would cause issues")
game.ReplicatedStorage.RemoteEvent:FireServer(Instance.new("PointLight"))
Output:
sending real part
true
sending fake part that doesnt meet the conditions
false
sending something that would cause issues
false
This system seems to hold up and is somewhat organized. It allows the server-side checks to be put together in an organized way and as an added bonus makes sure it can’t throw errors. Is there a better way to make a system like this? Is this system even a good idea to begin with?
This concludes my findings, but I just want to confirm. Am I on the right track here? All these methods seem to hold up pretty well and seem effective, but I’m definitely not an expert when it comes to these checks.
Thanks for reading and any help is appreciated.