Separating the client and server, and assigning tasks to each is one of the most important code-design decisions you will make during the creation of your game. Lets break down the main components you will need to go over:
Feedback Mechanisms
One of the most complex to maintain. Feedback mechanisms are anything which indicates the action is happening after the input, whether it is successful or not. Examples of this could be muzzle flash on a gun, sword slash sound on a melee weapon, unlocking sound on a chest, etc…
Feedback mechanisms can be separated into three sections: Player only, 3rd party only, or both. Player only and third party are relatively easy to get a grip on; you do the processing locally, to those who want to see it. When you intend for the entire server to see the effect, including the person who triggered it, that is when it gets tricky.
Referring back to our previous example: muzzle flash. In any feedback mechanism, you want the feedback action to appear instant to the player. In the meantime, you also want to replicate to the other players as fast as possible. How do you achieve this? Simple, you do both. The player handles instant processing of the action, generating the necessary feedback mechanisms. In the meantime, the server replicates the action to all other clients, ignoring our local player, since he already got the feedback.
On a quick side note, you should do the same checks you do in the server at the client too. We wouldn’t want the client getting feedback for something that ends up not happening.
Checks and balances
This is what you will hear any time you post about FilteringEnabled / Experimental mode on this forum. To keep your game safe, you must check every single thing that comes trough a remote event from the client to the server.
Do not trust the client
Movie-like quotes adverting to danger aside, what might be news to you, is that you should run the checks on both the server and client. Why is that you might ask? Simple, performance!
As a general rule of thumb, the client is much more processing-capable than the Roblox servers are. Use this to your advantage! If you avoid sending RemoteEvent calls to the server, by doing the checks first in the client, you safe processing power for other tasks!
This isn’t a hard-line rule; specifically in mobile-oriented games, you might want to avoid client processing of unnesesary checks
Damage and other mechanics
While this is the easy part, it’s also where most developers get things horribly wrong, and expose their games to unnecessary exploits.
Remember, just because you are checking for things in the client, in all of the scripts that will fire the RemoteEvent, this does not mean it won’t be fired at other times. One of the most common exploits around is the ability to fire RemoteEvents as the client. Expect exploits to fire your events with random assortments of arguments attempting to cause a change in server behaviour. A common example would be killing all players for an unprotected report-damage event.
Remember, all calculations, and all mechanics should be done strictly in the server. You cannot trust the client to do any of the heavy-work here, as an exploiter could easily rig the system in their advantage.