Remotes is a network wrapper for Roblox’s remotes which adds a few handy features which I find using all the time.
Setup should be pretty similar to how you code with them already (with the exception of changing how OnServerInvoke works), so it should be natural to all Roblox developers & easy to integrate to!
Features
Integrated Type Checking — Require clients to send over proper types!
Details & Examples
Values sent from the client to the server can never be trusted. You must implement server-sided sanity checks to ensure that whichever parameter the client sends exists and is of the proper type, depending on what you plan to do with the value.
Remotes lets you pass in a list of parameters, formatted very similarly to Luau type-checking.
-- Imagine a BuyItem function above
Remotes("BuyItem"):OnServerEvent:Connect(function(Request, Name: string, Count: number?)
local Item = Content.Items[Name]
if not Item then
return
end
BuyItem(Name, Count or 1)
end, {"string", "number?"})
In the example, {"string", "number?"}
is the second argument to OnServerEvent, meaning that before the callback runs, Remotes will verify that the first 2 values sent by the client both exist & are of proper types. Just like in Luau, string
indicates that the first value is a string, and number?
indicates that the second value can be a number or nil.
You can also supply unions in a list format, so if Count
could be either a boolean or a number, you would format the list like so:
{"string", {"number", "boolean"}}
Debounce — Limit how often a remote can execute server-sided code, either per-player, or globally!
Details & Examples
Tired of making lists for every Connection to OnServerEvent (and so on) to limit how often the server can process a request? Look no further, because Remotes offers a function inside of the Request
object, Debounce
, which will limit how often the callback will run. This ‘debounce’ is paired per-connection, so if you have two OnServerEvent callbacks with Remote and run Debounce
on one of them, the other one will still run independently.
Here’s a common use case: You want to give the client some values which are expensive to calculate, or maybe it’s something that the player can only do every 10 minutes, like opening a chest on the map.
Remotes("OpenChest"):OnServerEvent:Connect(function(Request, Chest: Instance)
local Player = Request.Client
Request:Debounce(Player, 600)
-- To debounce globally, do Request:Debounce(nil, 600)
-- Award player the contents of the Chest & remove it from the map
end, {"Instance"})
You can also use Debounce to resume after certain code has ran… if that’s your thing! (And yes, if your code errors while a debounce is active, it’ll allow for requests again in 5 seconds )
Remotes("DoExpensiveCalculation"):OnClientEvent(function(Request)
Request:Debounce() -- Sets a debounce; callback won't run again
-- Do expensive stuff!
Request:Debounce() -- Clears a debounce; callback will run on the next OnClientEvent!
end)
Improved OnServerInvoke — Expect a consistent return format back to the client!
Details & Examples
This wrapper restricts how you can return using OnServerInvoke to make working with them safer & more consistent. Instead of the response being a traditional Tuple, think of how HttpService:RequestAsync’s response works.
This is great, as dealing with exceptions from the server is super easy. For example, if you have any pop-ups for your game when you might not have enough cash to buy something, or if you can’t access an area yet, you can always return that message as the exception and display it in your UI!
You’ll never have to deal with questioning how you formatted the response for each remote & if you included a Success value or not.
Client-side
When you call InvokeServer on the client, it will return a Response
object which contains details about the request.
-- Format of a Response object
Response = {
Success: boolean,
Exception: string?,
Data: any?
}
Success
is whether or not the Request ended in an exception. True indicates that the Request was Closed successfully.
Exception
is the error message if an exception was raised on the server.
Data
is an optional value for sending back data to the client. This can be whatever you choose.
Note: Remotes doesn’t support Tuple values, so if you have any specific use cases to return one, make sure to pack them into Data.
Exceptions can be raised on the server through the following means.
- Manually through
return Request:Raise(exception: string)
to indicate that the server is unable to finish processing the request (e.g. The player doesn’t have enough cash to buy an item) - The Luau code on the server ran into its own exception (e.g.
workspace:FindFirtChild
) - The Request didn’t run the callback in the first place due to invalid types being sent to the server, or a Debounce currently being active on the server.
local Response = Remotes("GetCash"):InvokeServer()
Gui.CashLabel.Text = Response.Data.Cash
Server-side
-- Imagine a SessionManager module to import player data
local Remote = Remotes("GetCash")
Remote:OnServerInvoke(function(Request, IncludeCoins: boolean?)
local Player = Request.Client
local Session = SessionManager:Get(Player)
if not Session
return Request:Raise("Session is invalid") -- Can't process this request anymore
end
return Request:Close({ -- Closing the request successfully & returning Data!
Cash = Session.Data.Cash,
Coins = IncludeCoins and Session.Data.Coins
})
end, {"boolean?"})
Setup
-
Insert a ModuleScript, name it “Remotes”, and use the code from the GitHub gist. Alternatively, use the Roblox Model.
-
Insert any RemoteEvents, RemoteFunctions, or UnreliableRemoteEvents you may use for your game under the Remotes module. You can nest remotes into folders as well.
-
Grab a Remote by requiring the modulle and calling
Remotes("RemoteNameHere")
. You can use the methods similarly to how you usually would, but with the extra functionality. EachOnServerEvent
,OnClientEvent
, andOnServerInvoke
method returns a Request object which can be used to limit requests (debounce), as well as grabbing the Client that sent the request (if on the server). -
Make sure that when using OnServerInvoke, you return either
Request:Raise
to raise an exception, orRequest:Close
to close the request & return any values back to the client. Returning values outside of this format isn’t recommended. -
For any other questions, look up the examples in this post, the place file below, or write code with it! Remotes has type-checking for Luau so you can read up descriptions on each function.
“Clickin’ Cookies” example place
If you want to see how Remotes can be utilized in a game, feel free to inspect the source of the example place, Clickin’ Cookies!
Hopefully someone can find this resource useful! If you did, or have any complaints, or if it’s just not for you, let me know your thoughts by replying to the post so I can improve my resources in the future!!
Note: OnClientInvoke was not implemented in this module due to how unsafe it is to call. If you need a response from a client, I recommend using regular RemoteEvents / UnreliableRemoteEvents.