Shooting gun doesn't work as intended

My FPS shooter has a problem currently where the client viewmodel appears to be shooting a gun but the server does not allow it sometimes and the reasoning behind it is

if ((os.clock() - LastShot) >= (60/RPM)) then blah blah blah end

I want to keep this piece of code in as it will prevent exploiters turning a pistol with a comically large magazine into a minigun that atomizes everything in front of it

The client also has this piece of code in it to keep the visuals synced to the gun and make it look like the game isn’t held together with a piece of string but since the server and client don’t run at the same time, the time for both will be different which will be problematic

The solutions I have tried are

  1. task.wait(60/RPM)
    This was what I was doing before I noticed the problem was occurring
  2. Remote Functions instead of Remote Events
    This almost works but there are delays between shots that I don’t want
  3. Slightly extend the wait time per shot on the client just enough
    This is what I’m currently doing but this does not fix if the client lags for a little bit and they’re holding down the fire button and their ammo count goes down which could heavily change the outcome of a gunfight

I am thinking of having a value that the server controls that lets the client check if it can shoot but this sounds a little bit hacky for me and I’d prefer a cleaner approach but if this is the best solution then tell me

Now I need better solutions than these because I have no idea of how to properly fix this

Heres my suggestion, you might want to process the fire rate on the server. And yes, yes, this may impact users with throttled connections or just poor internet overall, however it will make your values more consistent across the server. Plus, in the future or even possibly now, who knows when exploiters might make a way to wind their lua runtime faster then the speed of light and then you have another minigun.

If your communicating between serverscripts use Bindable Events as clients have no way to intercept their values.

Theres always the option to run a dedicated serverscript for the client… and while it may be a little impractical you could then run a localscript to just broadcast the values to it.

Just some ideas.