I’m trying to replicate an OOP class representing a player, and let the local player get access to more sensitive data in their object. I.e, I don’t want random players to be able to see a player’s inventory, a player’s achievements, a player’s gamepass data, etc.
So, here’s the deal.
Either I do FireClient to everyone, with a special exception to the local player
OR
I do FireAllClients with both versions and hope that exploiters don’t read the data they’re not supposed to see.
Which one should I pick? This is assuming FireAllClients isn’t just FireClient being looped to all players to begin with.
Since you’re aiming to pass data to a specific Client, you should definitely use :FireClient(Player)
.
Aside from the fact that it requires less scripting since it only fires for the specified player and you simply need to listen for .OnClientEvent
, it’s also safer in terms of security: :FireAllClients
would enable exploiters to edit the LocalScript
where the event listener is located, and allow them to remove the exception filter to have the remote’s data passed to themselves.
I mean in terms of firing a remote too quickly. I may end up passing quite a lot of data each time a remote is fired, as it includes not only the player’s class, but any related class (character data, for instance), which is why I’m so hesitant on this. Unless it well and truly does not matter, such as FireAllClients being shorthand for a while loop through every player using FireClient.
You can pass a tuple with quite a bit of data to the client if you can do so (I don’t know your exact situation).
remote.OnClientEvent:Connect(function(...)
local args = {...}
--random examples
local inventory_data = args[1]
local achievements = args[2]
end)
I’m not concerned about the number of arguments, just the volume of data compared to how often a remote is being fired possibly hitting the limit.
Yes, I know. I was saying if you don’t want to fire the client an unneeded amount of time you can try packing more info into one fire. The limit appears to be 50 kbps from what I have seen online.
I’m already packing everything within a single fire. It’s firing it once for each individual player that I’m concerned about. You’re thinking about the data itself being what’s fired multiple times.
Edit: If all else fails, here’s an idea:
FireAllClients with the non-local data.
Have a check on the local player’s computer to see whether or not it’s them, if it is-- ignore the data.
FireClient exclusively to the local player with the sensitive data.
If FireAllClients ends up being shorthand for a loop, this would be less efficient. Otherwise this could solve the problem.
Even assuming that under the hood :FireAllClients()
is a loop that uses the :FireClient()
method for every player, you shouldn’t be worrying about sending too large/many requests to a client unless their amount or the size of the passed data is absurdly high, especially to the point where it would cause the remote queue to exhaust and drop the request.
Keep also in mind that - quoting the official bandwidth limitation paragraph - Roblox servers can send up to 50 KB/s of data per client, therefore sending several requests to multiple clients at once should not count each individual request towards the rate limit, but instead group them based on the receiving client (and as far as other users have reported, this limit should actually not be enforced; the server would not refuse to send any amount of data, although the end user’s experience would likely be affected negatively).
Bandwidth Limitation Paragraph
For most devices and connections, a Roblox server can only send and receive about 50 KB/sec of data to each client, not including physics updates. That said, it is highly recommended to maintain a lower value during normal gameplay as sudden spikes in data transfer can cause lag and an overall subpar user experience.
Every time a remote event is fired or a remote function invoked, a packet of data is sent over the network between the server and client. This packet is counted towards the 50 KB/sec limit. If too many packets are sent (remote event or function used often), or too much data is sent per packet (lots of large arguments to the event or function), the latency of the connected clients can be adversely affected.
On a side note, no. I did not spend 1 hour typing this - I simply could’ve accidentally fallen asleep on my keyboard.
Correct me where and if I’m wrong, it’s 4AM and I’m rather sure I wouldn’t’ve come up with some of these concepts if I was bit more stable. I’m sorry if my answer up here makes no sense at all.
In practice, you would use FireAllClients if all clients need to see information from the server in a specific area where the server cannot interract, such as user interface. Looped FireClient allows filtered recepients, limiting the count of clients you want to fire the information to, this avoids leaking data to exploiters.
Do not use FireAllClients with checks on their scripts. Exploiters who are creative enough can dump the script through decompilers and then change it and replace it before run time. Also adding protective layers here are false security, as they only slow them down.
Don’t worry, I know what I’m doing. In fact I’m pretty happy with the system I have going on right now, and I wouldn’t mind explaining it in the hopes that it saves someone time.
For each OOP class, I have 3 modules. One is for shared code, one is for client code, and one is for server code. There’s a bunch of automation involved that essentially makes the code completely compatible with one another-- if you do core.players on the server, you will get the server’s version of the Player class, and vice-versa.
Another layer of automation I have is that, beyond having functions to simplify the process of firing remotes, I have code run on the server that then proceeds to automatically look at code on the client, find functions that are only present on the player’s client version of the module and convert that into a function that gets the arguments and passes them through a remote.
This is surprisingly easy & quick to do and can end up saving a lot of time. Here’s an example using my game:
Not that long, huh? If your game is structured similarly to mine, adding these few lines in could really make replication effortless.
This effectively means that if there is a function on the client that doesn’t exist on the server, you can run it like a regular function on the server and it will automatically replicate to the correct player.
There are also various other things I’ve used for automation, such as modules getting sorted upon the game starting, so you can have all modules be neatly packed together and avoid scrolling from replicatedstorage to serverstorage back and forth over and over again, and probably some other things I’m forgetting.
Tl;dr code is being hidden, stuff is being automated, tampering with code won’t replicate to other players. It takes time to set stuff up like this, but wow it pays off.
If anyone has any other ideas for automation, please message me. This is kind of offtopic for this thread, haha.