How to check if a player is spamming a remote too fast?

You can use os.time() on the server :stuck_out_tongue: and just have a hashed table with last uses stored by userid.

I don’t see what use this would be on its own. What would you do with this data?

You could create a table of tick() for each player, and each time you fire set a variable like

local players = {}
newtick = tick()
if newtick > players[p]  + 1 then
print("All good")
end

This is just an example, so if it’s not enough time you can just change it up and make it better.

EDIT: Also players[p] in this situation would be the old tick() and after if it prints all good set players[p] to the new tick()

This is just another flavor of “time since last event” check. I’ve explained above why this isn’t a good general-purpose approach for flood control.

os.time() can be called on the server. So the argument of trusting the client is invalid in this case. That is why I don’t really understand why you don’t think it’s a simple way to prevent the spamming of remotes.

I know os.time() can be called on the server, I just don’t see how it’s useful. Let me illustrate. I’m playing your game, and I click 4 times to shoot a weapon, say each ~0.2 seconds apart. Each time I click, the game client fires a RemoteEvent, indicating that I fired a shot. Now, many miles away (possibly thousands), my RemoteEvents arrive at the game server, all at the same time and get processed (OnServerEvent) all on the same tick, with the same os.time stamp (they don’t need to be exact, but suppose the differences are way less than the original 0.2 seconds). Am I now a spammer with your system? I would not be with my system, because it is very forgiving of individual server arrival time differences.

1 Like

Yeah I guess you are right about that, but it’s a simple way to do it.
I’ll read your way of doing it because I haven’t had time to read it completely yet.

From what I understand and from personal experience, imagine if you have more than 1 player. If you have a denounce in that Event, and both players fire at the same time; It will only swing for one of the players and then wait(.5). As far as the solution that I’m trying to figure out, I simply have a Check for each time a player clicks every second. If clicked, Check = true. Waits(1) Check = false. Of course, this is server-side.

Other RemoteEvent calls do not have to wait for previous calls to finish in order to spawn up.

1 Like

This seems like a good method of keeping traffic under control.

But what if I were to have a game with multiple cooldowns for multiple event-based actions such as the sword swinging and an action such as a sword skill that is longer and is expected to last 5 seconds, with a 3 second cooldown after it is used. Is there a way to verify that the player is not doing anything else while the skill is in use and to ensure the skill isn’t used for another 3 seconds once on cooldown with the leaky bucket algorithm?

You stated earlier that you should keep each event in its own “leaky bucket”, but with this approach what if the exploiters were to use the sword attacks and the skill all at once? In this case, both buckets would see it as normal traffic because the buckets don’t account for each other and the time the player has spent doing their accumulative actions.

You can keep them seperate while having some sort of “tether” to make sure they’re not spamming multiple things at once

Specifically, what would this “tether” look like in pseudo code and/or code?

I fail to come up with a method that can validate that no other action is in use without something like a Boolean value on the server and we already know that that wouldn’t work due to latency.

The specific example you outlined is something you’d handle in game code, a layer up from the remote event processing. You can still have seperate leaky buckets for each event type, but you have to also process input in the order you get it, and if something like the 3-second skill is meant to suppress normal basic attacks, you don’t change code at the event processing level for that, you just store the skill end time associated with the player and invalidate or defer the mutually-exclusive attacks during that cooldown window (in server time).

It’s a game design question as to whether you invalidate the attacks (completely disregard the events) or defer them (queue them up to be processed at maximum rate as soon as the skill ends). You can also do both–throw away attacks during most of the skill cooldown, but have a “fuzzy” tolerance for attacks that arrive right when the cooldown is about to expire. You could choose to only queue up an attack that is within some window of time around when the skill is ending, to allow for the possibility that the player saw the skill end before the server cooldown was quite expired.

One common way of doing this is to make something with, say a 3-second cooldown, not refresh the UI on the client for 3 seconds, but on the server the cooldown timer actually gets set to something like 3 seconds minus half the player’s average round-trip ping time. Or even a fixed-size allowance. It’s only exploitable to the degree you let it be with your choice of tolerance time.

1 Like