Commands are network messages sent from one Entity to another Entity in the networked World. Functionally equivalent to standard RPCs, commands bind to public methods accessible on the GameObject that CoherenceSync sits on.
In the design phase, you can expose public methods the same way you select fields for synchronization: through the Configure window on your CoherenceSync component.
The selected public methods will be exposed as network commands in the baking process.
The button on the right of the method lets you choose the routing mode. Commands with aSend to Authority Only
mode can be sent only to the authority of the target Entity, while ones with the Send to All Instances
can be broadcasted to all clients that have a copy of this Entity. The routing is enforced by the Replication Server as a security measure so that outdated or malicious clients don't break the game.
To send a command, we call the SendCommand<>
method on the target CoherenceSync
object. It takes a number of arguments:
The type argument (within the <
and>
) must be the type of the receiving MonoBehaviour. This ensures that the correct method gets called if the receiving GameObject has components that implement methods that share the same name.
If there are multiple MonoBehaviours of the same type, the command is only sent to the first one in the hierarchy which matches the type.
The first argument is the name of the method on the MonoBehaviour that we want to call. It is good practice to use the C# nameof
expression when referring to the method name, since it prevents accidentally misspelling it, or forgetting to update the string if the method changes name.
The second argument is an enum that specifies the MessageTarget
of the command. The possible values are:
MessageTarget.All
– sends the command to each Client that has an instance of this Entity.
MessageTarget.AuthorityOnly
– send the command only to the Client that has authority over the Entity.
MessageTarget.Other
- sends the command to every Entity other than the one SendCommand is called on.
Mind that the target must be compatible with the routing mode set in the bindings, i.e. Send to authority
will allow only for the MessageTarget.AuthorityOnly
while Send to all instances
allows for both values.
Also, it is possible that the message never sends as in the case of a command with MessageTarget.Other
sent from the authority with routing of Authority Only.
The rest of the arguments (if any) vary depending on the command itself. We must supply as many parameters as are defined in the target method and the schema.
Here's an example of how to send a command:
We don't have to do anything special to receive the command. The system will simply call the corresponding method on the target network entity.
If the target is a locally simulated entity, SendCommand
will recognize that and not send a network command, but instead simply call the method directly.
Sometimes you want to inform a bunch of different Entities about a change. For example, an explosion impact on a few players. To do so, we have to go through the instances we want to notify, and send commands to each of them.
In this example, a command will get sent to each network Entity under the authority of this Client. To make it only affect Entities within certain criteria, you need to filter to which CoherenceSync you send the command to, on your own.
Some of the primitive types supported are nullable values, this includes:
Byte[]
string
Entity references: CoherenceSync, Transform, and GameObject
In order to send one of these values as a null (or default) we need to use special syntax to ensure the right method signature is resolved.
Null-value arguments need to be passed as a ValueTuple<Type, object> so that their type can be correctly resolved. In the example above sending a null value for a string is written as:
(typeof(string), (string)null)
and the null Byte[] argument is written as:
(typeof(Byte[]), (Byte[])null)
Mis-ordered arguments, type mis-match, or unresolvable types will result in errors logged and the command not being sent.
When a null argument is deserialized on a client receiving the command, it is possible that the null value is converted into a non-null default value. For example, sending a null string in a command could result in clients receiving an empty string. As another example, a null Byte[] argument could be deserialized into an empty Byte[0] array. So, receiving code should be ready for either a null value or an equivalent default.
When a Prefab is not using a baked script there are some restrictions for what types can be sent in a single command:
4 entity references
maximum of 511 bytes total of data in other arguments
a single Byte[] argument can be no longer than 509 bytes because of overhead
Some network primitive types send extra data when serialized (like Byte arrays and string types) so gauging how many bits a command will use is difficult. If a single command is bigger than the supported packet size, it won't work even with baked code. For a good and performant game experience, always try to keep the total command argument sizes low.