Background
In normal client-server games, the server is authoritative meaning it has the final say over how the games state exists and is in charge of making sure the clients know the current game state. It does this by taking all of the game logic and running it instead of the clients* and then sending updates as it sees fit. The most basic building blocks of these mechanics are the [Command]
, [ClientRpc]
, and [TargetRpc]
attributes. These aren't super high level like the automatic syncing stuff like [SyncVar]
and NetworkTransforms
nor are they super low level like sockets.
*It does this to the extent possible by which to not introduce too much network bandwidth (causing poor performance) and complexity. So usually the client is responsible for simulating and predicting physics, lighting, and other intensive tasks while the server just syncs object state, positions, and provides game notifications for playing client-side sounds and changing the UI.
How they differ
[Command] - The [Command]
attribute is called by a client (!) and executed by the server on that same object. The client can only call this on objects it has authority over. These usually relay some sort of client intent like fire my gun or send a chat message. Ignoring all the automatic syncing (SyncVars
, NetworkTransform
, etc) this is the only way for the client to do something on the server and as such all client network actions that have the chance to change the game or affect other clients need to be a [Command]
that the client can call to run on the server.
[ClientRpc] - The [ClientRpc]
attribute is called on the server and executed on all of the clients that are currently connected to the server for a given object. [ClientRpc]
is most commonly used to notify the clients of game changes like a change in score or that they have died (to play sound and death animations on all players' screens).
[TargetRpc] - Added in Unity 5.4 - The [TargetRpc]
attribute is the same as above but is only executed on a specific client when called on the server. The server passes a NetworkConnection
object to denote which client it would like to execute the TargetRpc
on.
A super helpful overview of all this (including a nifty diagram) can be found in the UNET tutorial series.
When server authority matters
What I described above is the most common uses for these type of commands where server authority is very important (like competitive games). More casual games where cheating isn't a huge deal (coop games, games where you trust the other players to not cheat) might be structured differently.
An example might be a game where you fire a gun to shoot an enemy. In a non-competitive game where cheating isn't an issue, I might have a ShotObject
command which clients call with the objects they shot. This is really easy to cheat but low complexity. In a competitive multiplayer game however, I would need have a FireGun
command that takes no arguments and simulates the Raycast for the gunshot on the server alone so clients couldn't cheat. This introduces the added complexity of backing up the server simulation to when the client shot, doing the raycast, and then proceeding with the game.
The basic rule here is that when server authority matters, run as much as you can on the server. When it doesn't you're free to do what you want.
Command
when it's a client action that requires a response from the server, like sending aGET\POST
http request and expecting a result, and useRpcClient
when it's an event that happens due to the update loop or whatever on the server, and the clients need to be modified, similar to aPUT
http request. \$\endgroup\$