Migrate from 1.X
This section describes the breaking changes introduced in version 2.0 of the Unity Transport Package (UTP). It also explains how to update projects written for version 1.X.
In most use cases, there’s no need to perform any additional steps to migrate from 1.X to 2.0. The core APIs (like NetworkDriver) remain the same, and the most significant changes are limited to specialized scenarios, such as custom network interfaces.
Collections-related errors following upgrade
It is possible that upgrading a project from version 1.X to 2.0 will result in errors like the following appearing in the console:
Unity.Collections/NativeParallelHashSetExtensions.gen.cs(17,51): error CS0246: The type or namespace name 'NativeHashSet<>' could not be found (are you missing a using directive or an assembly reference?)
Unity.Collections/UnsafeParallelHashSetExtensions.gen.cs(1084,78): error CS0246: The type or namespace name 'UnsafeHashSet<>' could not be found (are you missing a using directive or an assembly reference?)
There errors can occur when upgrading the Collections package from version 1.2 to 2.X. Closing and restarting the editor is usually enough to get rid of the errors.
Editor version support
UTP 1.X supports Unity Editor 2020.3 and up, but 2.0 only supports 2022.2 and up to keep the Collections package dependency up to date. Unity Editor 2022.2 brings changes to the core Unity Engine runtime, allowing more code to be Burst-compiled. UTP benefits from this through increased performance.
UTP 1.X remains fully supported on LTS versions 2020.3 and 2021.3, and Unity will continue to release bug fixes and improvements. However, some features (like WebSocket support) will only be available in UTP 2.0 and up.
DataStreamReader/DataStreamWriter moved to Collections
UTP 2.0 moves the DataStreamReader and DataStreamWriter APIs to the Collections package to make them more widely available outside UTP. As a result, updating to UTP 2.0 might require you to add a using Unity.Collections directive at the top of files using the DataStreamReader and DataStreamWriter APIs.
The APIs are mostly unchanged, except for raw pointers. Unity.Collections.LowLevel.Unsafe namespace now provides the raw pointer methods with Unsafe appended to their names. For example, the method WriteBytes(byte*, int) is now WriteBytesUnsafe(byte*, int).
Protocol incompatibility
The custom communication protocol UTP uses to implement connections over UDP has changed in a backward-incompatible manner, which means clients running UTP 2.0 or later can't connect to servers running 1.X, and vice versa. If you try to establish a connection between UTP 2.0 and UTP 1.X, UTP returns a connection failure after the usual timeout.
Due to the incompatibility between UTP 2.0 and UTP 1.X, you must either ensure that you update clients and servers simultaneously or disallow older clients from connecting to updated servers. Alternatively, you can create different endpoints for UTP 1.X and 2.0 servers to smooth the transition while you update older clients.
These breaking changes improve bandwidth efficiency, simplify the protocol, and lay the foundations for better forward compatibility.
Custom network interfaces
The updates in UTP 2.0 heavily modify the INetworkInterface API used to implement custom network interfaces (the low-level layer to send and receive packets) to simplify it.
UTP 2.0 introduces the following breaking changes to custom network interfaces:
- UTP 2.0 no longer has the idea of
NetworkInterfaceEndPoint; the more generalNetworkEndpointreplacesNetworkInterfaceEndPoint. As a result, you don't need to implement conversion logic betweenNetworkEndpointandNetworkInterfaceEndPointanymore, so INetworkInterface omitsCreateInterfaceEndPointandGetGenericEndPoint. - You no longer need to create a
NetworkSendInterfacethroughCreateSendInterface.ScheduleSendhandles send operations, which get passed aPacketsQueuecontaining the packets to send. - The
ScheduleReceivemethod doesn't use the (now obsolete)NetworkPacketReceiverto propagate received packets to the rest of UTP. Instead, implementations ofScheduleReceiveshould fill thePacketsQueuepassed in with the received packets. - Implementations of
INetworkInterfacemust now be fully compatible with Burst. If an implementation is incompatible with Burst, you can wrap it into a compatible implementation with the newWrapToUnmanagedextension method. - You must now create NetworkDrivers using a custom network interface using the static
NetworkDriver.Createmethod. For example,NetworkDriver.Create(new MyCustomInterface())creates aNetworkDrivernamed MyCustomInterface(). Directly constructing a NetworkDriver with new is deprecated. INetworkInterface.Initializenow takes another parameter: a reference to the packet padding, and you can increase this value to reserve space for headers.
These breaking changes simplify and increase the flexibility of the interface, making it easier to create custom network interfaces.
Pipeline stages
UTP 2.0 don't introduce changes to how you write custom pipeline stages. However, the mechanisms you should use to register and get the identifier of a pipeline stage have changed:
- Instead of registering a custom pipeline stage with
NetworkPipelineStageCollection.RegisterPipelineStage, useNetworkDriver.RegisterPipelineStage. You must do this on every instance ofNetworkDriverthat uses the custom pipeline stage. - Instead of retrieving the ID of a pipeline stage with
NetworkPipelineStageCollection.GetStageId, use the staticNetworkPipelineStageId.Getmethod.
These breaking changes remove Burst-incompatible APIs, allowing you to use more of UTP with Burst-compiled code.
For more information, see the section on using pipelines.
Other breaking changes
UTP 2.0 also introduces the following breaking changes:
- You must now complete a
NetworkDriver.ScheduleUpdatejob when notifying the remote peer of a disconnection after callingNetworkDriver.Disconnect. In 1.X,NetworkDriver.ScheduleFlushSendwas enough to tell a remote peer of a disconnection, but this isn't the case with UTP 2.0. This change supports new protocols, such as WebSockets, where disconnecting might involve more work than simply sending a message. - Using
SimulatorPipelineStageInSendis now deprecated. Instead, use SimulatorPipelineStage and configure the newApplyModeparameter to the direction desired (send, receive, or both). NetworkSettings.WithBaselibNetworkInterfaceParametersis now deprecated. You can no longer configure the maximum payload size; UTP handles the payload size automatically. However, you can configure the receive and send queue sizes withNetworkSettings.WithNetworkConfigParameters.- UTP 2.0 removes
NetworkSettings.WithDataStreamParametersandNetworkSettings.WithPipelineParameters. You no longer need to manually configure either of these parameters, so the methods are unnecessary. You can safely delete calls to these methods. - You no longer need to configure read and handshake timeouts through
NetworkSettings.WithSecureClientParametersandNetworkSettings.WithSecureServerParameters. Instead, UTP derives the values automatically from other configuration parameters. You can safely remove these settings from these calls.