Managing Roblox Remote Events and Remote Functions

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.
    Using table.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

  1. Getting the Remote: We first retrieve the remote object using game:GetService("ReplicatedStorage").Remotes. This is assuming the remotes are stored under ReplicatedStorage in a folder called Remotes.
  2. 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 by UserId.
  1. 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 with RemoteFunction, we block multiple requests from the same player at the same time.
  1. Returning Values:
  • For RemoteFunction, we allow the callback to return multiple values, using the table.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.
  1. 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 on Calls[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:

  1. Create a RemoteFunction or RemoteEvent: In ReplicatedStorage, create a RemoteFunction or a RemoteEvent, then parent it to the Remotes folder.
  2. 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:

  1. Create a RemoteFunction or RemoteEvent in ReplicatedStorage under Remotes.
  2. 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.

  1. Verify the argument with typeof().
  2. 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.

2 Likes