Recently, I realized I could mass spam my remote from my client to claim my daily reward multiple times in fraction of seconds before the server updates, that’s when I learned about remote spamming. That’s why today I’ll be showing you how to handle this without having to copy paste a code that checks if the player fired a remote over and over for each remotes.
What We’ll Cover
- Handling the RemoteFunctions/ RemoteEvents requests of player
- Set call backs limiter per player preventing Abuse.
Returning multiple values from the server to the client.
Usingtable.unpack
to handle variable arguments.
Why Is This Useful?
In multiplayer games, it’s super important to prevent players from spamming remote calls. These can overload the server or cause unexpected behavior. By limiting how often each player can fire a callback, we can ensure the server stays performant and responsive.
The Code
Here is the completed script for handling multiple remote callbacks in a module script:
local Remotes = game:GetService("ReplicatedStorage").Remotes
local Calls = {}
function ListenToRemote(RemoteName:string,Callback)
local Remote = Remotes:FindFirstChild(RemoteName)
if not Remote then
warn("Could not find remote:",RemoteName)
return
end
if Remote:IsA("RemoteFunction") then
Remote.OnServerInvoke = function(plr,...)
local Id = plr.UserId
if not Calls[Id] then
Calls[Id] = true
else
print("Returning, callback limit exceeded")
return
end
local ReturnedValues = {Callback(plr,...)}
Calls[Id] = nil
return table.unpack(ReturnedValues)
end
elseif Remote:IsA("RemoteEvent") then
Remote.OnServerEvent:Connect(function(plr,...)
local Id = plr.UserId
if not Calls[Id] then
Calls[Id] = true
else
print("Returning, callback limit exceeded")
return
end
Callback(plr,...)
Calls[Id] = nil
end)
end
end
return ListenToRemote
How It Works
-
Getting the Remote: We first retrieve the remote object using
game:GetService("ReplicatedStorage").Remotes
. This is assuming the remotes are stored underReplicatedStorage
in a folder calledRemotes
. -
Handling
RemoteFunction
:-
RemoteFunction
enables synchronous calls, which mean the server waits for the response from the client.
-
- The
OnServerInvoke
event is used to handle the player’s requests. In such a way, when a player calls this remote, the server will execute the callback and return the results back to the client.- In order for one player to not be able to trigger multiple callbacks at once, use a
Calls
table, which keeps track of player requests byUserId
.
- In order for one player to not be able to trigger multiple callbacks at once, use a
- Handling RemoteEvent:
-
RemoteEvent
is asynchronous, meaning the server does not wait for a response from the client. The event handler is fired whenever the client calls the remote. - We use the
OnServerEvent
event to connect a function that executes the callback logic. Like withRemoteFunction
, we block multiple requests from the same player at the same time.
- Returning Values:
- For
RemoteFunction
, we allow the callback to return multiple values, using thetable.unpack
function to return the values correctly from the table returned by the callback. - For
RemoteEvent
, we don’t need to return anything, but we still execute the callback logic.
- Callback Limiting:
- The
Calls
table keeps track of whether the player has already called a remote. If he then makes another call before processing has finished, we block it by checking up onCalls[Id]
and output a message.
How to Use It
You can use this system with any remote function or event you may have in your game. Here’s how it is set up:
-
Create a RemoteFunction or RemoteEvent: In
ReplicatedStorage
, create aRemoteFunction
or aRemoteEvent
, then parent it to theRemotes
folder. -
Listen for the Remote: The
ListenToRemote
function should be called from within a server script. Here’s an example:
local ListenToRemote = require(game.ServerScriptService:WaitForChild("ListenToRemote"))
-- Configure a RemoteFunction or RemoteEvent
ListenToRemote("MyRemoteFunction", function(plr, arg1, arg2)
-- Logic handling the callback
print(plr.Name, "called with", arg1, arg2)
-- Return multiple values
return "Success", arg1 + arg2
end)
ListenToRemote("MyRemoteEvent", function(plr, arg1)
-- Handle the callback logic
print(plr.Name, "triggered the event with", arg1)
end)
Testing the Code
To test the system:
- Create a
RemoteFunction
orRemoteEvent
inReplicatedStorage
underRemotes
. - Call the remote from a LocalScript in the client and observe the server behavior.
For instance, invoking a RemoteFunction
using a LocalScript:
local RemoteFunction = game.ReplicatedStorage.Remotes:WaitForChild("MyRemoteFunction")
local result1, result2 = RemoteFunction:InvokeServer(5, 10)
print(result1, result2) -- Should print: "Success", 15
And for RemoteEvent
:
local RemoteEvent = game.ReplicatedStorage.Remotes:WaitForChild("MyRemoteEvent")
RemoteEvent:FireServer(42)
Server Checks
Make sure to verify the sent data by the client, because exploiters can send whatever they want.
So let’s say we’re making a remote to buy an item in the shop.
- Verify the argument with
typeof()
. - Verify if the
ItemName
exist in our possible items to buy.
local ListenToRemote = require(game.ServerScriptService:WaitForChild("ListenToRemote"))
local Items = {
Banana = 5,
Apple = 3,
Juice = 4
}
ListenToRemote("BuyItem", function(plr, ItemName:string)
if typeof(ItemName) ~= "string" then return end -- checks if value is a string
if not Items[ItemName] then return end -- checks of item is in the shop
plr.leaderstats.Money -= Items[ItemName] -- removes the player money
end)
For more information on this you can check this page from the Roblox API
Conclusion
This system allows you to handle remote events and functions effectively while limiting how often players can trigger them. By using RemoteFunction
and RemoteEvent
properly.
If I’m doing anything wrong, please tell me I’ll update my code.