Interface IRpcCommand
An interface that should be used to declare a Rpc struct.
RPCs are "one-shot" messages that can be sent and received by both the client and server, and can be used for different purposes. E.g. Implementing a lobby, loading level logic, requesting to spawn a player etc. Unlike ghost SnapshotData, rpc messages are sent using a dedicated reliable channel and are therefore guaranteed to be received.
As they're reliable messages, RPCs are not meant to be used as a replacement for ghosts, nor for sending data that will change frequently, nor player commands (ICommandData and IInputComponentData). Why not? 1) There is a maximum number of reliable packets that can be in-flight at any given time. 2) Latency is introduced by the ordering guarantee of the reliability pipeline.
An RPC struct can contain any number of burst-compatible fields. However, once serialized, its size must fit into a single packet. Large messages are not supported (NetworkParameterConstants.MaxMessageSize and account for header sizes).
It is possible to partially mitigate this limitation by creating a custom INetworkStreamDriverConstructor and setting a larger MaxMessageSize (but that will only work in favourable conditions and networks (ensure thorough testing!)) or by adding a FragmentationPipelineStage stage into the reliable pipeline (channel).
Usage: To send an RPC declared using the IRpcCommand interface, you should create a new entity with your rpc message component, as well as a SendRpcCommandRequest (which will notify the NetCode system that it exists, and send it). It is best to do this with an archetype to avoid runtime structural changes:
m_RpcArchetype = EntityManager.CreateArchetype(..);
var ent = EntityManager.CreateEntity(m_RpcArchetype);
EntityManager.SetComponentData(new MyRpc { SomeData = 5 });
RPCs declared using the IRpcCommand will have serialization and other boilerplate code for handling the SendRpcCommandRequest request automatically generated. For example:
public struct MyRpc : IRpcCommand
{
public int SomeData;
}
will generate the following systems and structs:
- A struct implementing the IRpcCommandSerializer<T> for your rpc type.
- A system responsible for consuming the SendRpcCommandRequest requests, and queuing the messages into the OutgoingRpcDataStreamBuffer stream (for the outgoing connection), invoked via RpcQueue<TActionSerializer, TActionRequest>.
Because the serialization is generated by our source generator, only types recognized by the code-generation system (and that are available to use inside commands and rpcs) are going to be serialized. See TypeRegistryEntry for other details.
The OutgoingRpcDataStreamBuffer is processed at the end of the simulation frame by the RpcSystem, and all messages in queue attempt to be sent over the network (assuming the reliable buffer is not full, as mentioned).
To distinguish between a "broadcast" RPC and an "RPC sent to a specific client", see SendRpcCommandRequest.
Namespace: Unity.NetCode
Assembly: Unity.NetCode.dll
Syntax
public interface IRpcCommand : IComponentData, IQueryTypeParameter
Remarks
RPCs do not make any guarantees regarding arrival relative to ghost snapshots. E.g. If you send an RPC first, and then send a snapshot, you must assume that they'll be received in any order. However, all RPC network messages are received in the exact same order that they are "sent" (NOT "raised"!).