This is definitely more than you asked for so don’t be too afraid of my giant wall of text haha
To answer your question, ideally the client should tell the server it wants to fire a bullet, and then the server should tell all clients that a bullet was fired and they can do the physics for the bullets themselves.
Usually, you can have your gun logic run on the server and client, and, the client can tell the server what it wants to do (e.g. Fire), that way an exploiter can’t spam the remote to create a million bullets.
(You could also have the client who shot create the bullet immediately)
The downside there is if the server gun code and the client gun code aren’t in sync, e.g. maybe the client thinks its done reloading but the server doesn’t think that, maybe they reloaded during high ping and so the server started reloading late, that client might see a bullet even if the server doesn’t make one.
There’s a few ways to solve that, one is just to not create the bullet on the client and let the server tell them, which, obviously defeats the purpose of doing it on the client for the person firing. You could also have the server tell them to delete the bullet if they can’t fire. Or, you could have the server tell the client when the gun is/isn’t ready and just never have the client do any reload logic.
This question is actually a bit relevant to me, cuz, I’m working on a fun little project around bullet networking and bullet sync. You or others might be interested and since it’s on topic, so I’ll explain what I’m trying to do, but, it’s not really answering your question.
I am working on creating synchronized bullets using workspace:GetServerTimeNow()
(which isn’t out yet) and the way I do that is still the same, the client tells the server they want to fire a bullet, and then the server tells all the clients to make a bullet, but, it includes the time from that function so that the bullet can be animated based on that time.
Basically, what I’m going to end up doing is having the client send their current time based on that function. The server is then going to check their ping using the new ping API (which has changed at least once) and its going to make sure that the remote was received within twice their ping. I’ll also clamp their ping so its not higher than a second or two, so they can’t fire bullets minutes ago, that way a bullet will only appear to fire up to that long in the past.
I’ll be tracking the position and aim of their gun for that second or two, and then I’ll look back in the past and find whatever it was right around when they shot the bullet. Then I can create a bullet, starting there from the current time, and, the server will send an event to all clients telling them that a bullet was created at that position, at that time, and all clients will simulate the path of the bullet based on workspace:GetServerTimeNow()
which will keep the position synchronized across all clients.
It’s really over complicated and unnecessary, but, it’s been fun so far.