Network connection
Netcode + Unity Transport
The network connection uses the Unity Transport package and stores each connection as an entity. Each connection entity has a NetworkStreamConnection component with the Transport
handle for the connection. When the connection is closed, either because the server disconnected the user or the client request to disconnect, the the entity is destroyed.
To request disconnect, add a NetworkStreamRequestDisconnect
component to the entity. Direct disconnection through the driver is not supported. Your game can mark a connection as being in-game, with the NetworkStreamInGame
component. Your game must do this; it is never done automatically.
Note
Before the NetworkStreamInGame
component is added to the connection, the client does not send commands, nor does the server send snapshots.
To target which entity should receive the player commands, when not using the AutoCommandTarget
feature or for having a more manual control,
each connection has a CommandTarget
which must point to the entity where the received commands need to be stored. Your game is responsible for keeping this entity reference up to date.
Ingoing buffers
Each connection can have up to three incoming buffers, one for each type of stream: commands, RPCs and snapshot (client-only). IncomingRpcDataStreamBuffer IncomingCommandDataStreamBuffer IncomingSnapshotDataStreamBuffer
When a client receive a snapshot from the server, the message is queued into the buffer and processed later by the GhostReceiveSystem. Similarly, RPCs and Commands follow the sample principle. The messages are gathered first by the NetworkStreamReceiveSystem and consumed then by the respective rpc and command receive system.
Note
Server connection does not have an IncomingSnapshotDataStreamBuffer.
Outgoing buffers
Each connection can have up to two outgoing buffers: one for RPCs and one for commands (client only). OutgoingRpcDataStreamBuffer OutgoingCommandDataStreamBuffer
When commands are produced, they are first queued into the outgoing buffer, that is flushed by client at regular interval (every new tick). Rpc messages follow the sample principle: they are gathered first by their respective send system, that encode them into the buffer first. Then, the RpcSystem will flush the RPC in queue (by coalescing multiple messages in one MTU) at regular interval.
Connection Flow
When your game starts, the Netcode for Entities package neither automatically connect the client to server, nor make the server start listening to a specific port. In particular the default ClientServerBoostrap
just create the client and
server worlds. It is up to developer to decide how and when the server and client open their communication channel.
There are different way to do it:
- Manually start listening for a connection on the server, or connect to a server from the client using the
NetworkStreamDriver
. - Automatically connect and listen by using the
AutoConnectPort
(and relativeDefaultConnectAddress
). - By creating a
NetworkStreamRequestConnect
and/orNetworkStreamRequestListen
request in the client and/ot server world respectively.
Note
Regardless of how you choose to connect to the server, we strongly recommend ensuring Application.runInBackground
is true
while connected.
You can do so by a) setting Application.runInBackground = true;
directly, or b) project-wide via "Project Settings > Player > Resolution and Presentation".
If you don't, your multiplayer will stall (and likely disconnect) if and when the application loses focus (e.g. by the player tabbing out), as netcode will be unable to tick.
The server should likely always have this enabled.
We provide error warnings for both via WarnAboutApplicationRunInBackground
.
Manually Listen/Connect
To establish a connection, you must get the NetworkStreamDriver singleton (present on both client and server worlds)
and then call either Connect
or Listen
on it.
Using the AutoConnectPort
The ClientServerBoostrap
contains two special properties that can be used to instruct the boostrap the server and client to automatically listen and connect respectively.
In order to setup the AutoConnectPort
you should create you custom bootstrap and setting a value different than 0 for the AutoConnectPort
before creating your worlds. For example:
public class AutoConnectBootstrap : ClientServerBootstrap
{
public override bool Initialize(string defaultWorldName)
{
// This will enable auto connect.
AutoConnectPort = 7979;
// Create the default client and server worlds, depending on build type in a player or the PlayMode Tools in the editor
CreateDefaultClientServerWorlds();
return true;
}
}
The server will start listening at the wildcard address (DefaultConnectAddress
:AutoConnectPort
). The DefaultConnectAddress
is by default set to NetworkEndpoint.AnyIpv4
.
The client will start connecting to server address (DefaultConnectAddress
:AutoConnectPort
). The DefaultConnectAddress
is by default set to to NetworkEndpoint.Loopback
.
Note
In the editor, the Playmode tool allow you to "override" both the AutoConnectAddress and AutoConnectPort. The value is the playmode tool take precedence.
Note
When AutoConnectPort is set to 0 the Playmode tools override functionality will not be used. The intent is then you need to manually trigger connection.
Controlling the connection flow using NetworkStreamRequest
Instead of invoking and calling methods on the NetworkStreamDriver you can instead create:
- A NetworkStreamRequestConnect singleton to request a connection to the desired server address/port.
- A NetworkStreamRequestListen singleton to make the server start listening at the desired address/port.
//On the client world, create a new entity with a NetworkStreamRequestConnect. It will be consumed by NetworkStreamReceiveSystem later.
var connectRequest = clientWorld.EntityManager.CreatEntity(typeof(NetworkStreamRequestConnect));
EntityManager.SetComponentData(connectRequest, new NetworkStreamRequestConnect { Endpoint = serverEndPoint });
//On the server world, create a new entity with a NetworkStreamRequestConnect. It will be consumed by NetworkStreamReceiveSystem later.
var listenRequest = serverWorld.EntityManager.CreatEntity(typeof(NetworkStreamRequestListen));
EntityManager.SetComponentData(connectRequest, new NetworkStreamRequestListen { Endpoint = serverEndPoint });
The request will be then consumed at runtime by the NetworkStreamReceiveSystem.
Network Simulator
Unity Transport provides a SimulatorUtility, which is available (and configurable) in the Netcode package. Access it via Multiplayer > PlayMode Tools
.
We strongly recommend that you frequently test your gameplay with the simulator enabled, as it more closely resembles real-world conditions.