Skip to content

Commit 784bafa

Browse files
feat: Enable fragmentation for unreliable delivery (UTP) (1.0.0) (#1515)
* Add fragmentation to the unreliable sequenced pipeline * Add fragmentation for unreliable delivery * Test multiple delivery methods in adapter tests * Update CHANGELOG with latest change * Make the standard script happy...
1 parent 766d690 commit 784bafa

File tree

3 files changed

+60
-37
lines changed

3 files changed

+60
-37
lines changed

com.unity.netcode.adapter.utp/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ All notable changes to this package will be documented in this file. The format
77

88
- Removed 'Maximum Packet Size' configuration field in the inspector. This would cause confusion since the maximum packet size is in effect always the MTU (1400 bytes on most platforms).
99
- Updated com.unity.transport to 1.0.0-pre.8
10+
- All delivery methods now support fragmentation, meaning the 'Send Queue Batch Size' setting (which controls the maximum payload size) now applies to all delivery methods, not just reliable ones.
1011

1112

1213
### Fixed

com.unity.netcode.adapter.utp/Runtime/UnityTransport.cs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ namespace Unity.Netcode
1616
/// </summary>
1717
public interface INetworkStreamDriverConstructor
1818
{
19-
void CreateDriver(UnityTransport transport, out NetworkDriver driver, out NetworkPipeline unreliableSequencedPipeline, out NetworkPipeline reliableSequencedFragmentedPipeline);
19+
void CreateDriver(
20+
UnityTransport transport,
21+
out NetworkDriver driver,
22+
out NetworkPipeline unreliableFragmentedPipeline,
23+
out NetworkPipeline unreliableSequencedFragmentedPipeline,
24+
out NetworkPipeline reliableSequencedFragmentedPipeline);
2025
}
2126

2227
public static class ErrorUtilities
@@ -141,7 +146,8 @@ public static implicit operator ConnectionAddressData(NetworkEndPoint d) =>
141146
private NetworkConnection m_ServerConnection;
142147
private ulong m_ServerClientId;
143148

144-
private NetworkPipeline m_UnreliableSequencedPipeline;
149+
private NetworkPipeline m_UnreliableFragmentedPipeline;
150+
private NetworkPipeline m_UnreliableSequencedFragmentedPipeline;
145151
private NetworkPipeline m_ReliableSequencedFragmentedPipeline;
146152

147153
public override ulong ServerClientId => m_ServerClientId;
@@ -194,7 +200,12 @@ public SimulatorUtility.Parameters ClientSimulatorParameters
194200

195201
private void InitDriver()
196202
{
197-
DriverConstructor.CreateDriver(this, out m_Driver, out m_UnreliableSequencedPipeline, out m_ReliableSequencedFragmentedPipeline);
203+
DriverConstructor.CreateDriver(
204+
this,
205+
out m_Driver,
206+
out m_UnreliableFragmentedPipeline,
207+
out m_UnreliableSequencedFragmentedPipeline,
208+
out m_ReliableSequencedFragmentedPipeline);
198209
}
199210

200211
private void DisposeDriver()
@@ -210,10 +221,10 @@ private NetworkPipeline SelectSendPipeline(NetworkDelivery delivery, int size)
210221
switch (delivery)
211222
{
212223
case NetworkDelivery.Unreliable:
213-
return NetworkPipeline.Null;
224+
return m_UnreliableFragmentedPipeline;
214225

215226
case NetworkDelivery.UnreliableSequenced:
216-
return m_UnreliableSequencedPipeline;
227+
return m_UnreliableSequencedFragmentedPipeline;
217228

218229
case NetworkDelivery.Reliable:
219230
case NetworkDelivery.ReliableSequenced:
@@ -647,7 +658,6 @@ public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDel
647658
{
648659
// If data is too large to be batched, flush it out immediately. This happens with large initial spawn packets from Netcode for Gameobjects.
649660
Debug.LogWarning($"Event of size {payload.Count} too large to fit in send queue (of size {m_SendQueueBatchSize}). Trying to send directly. This could be the initial payload!");
650-
Debug.Assert(networkDelivery == NetworkDelivery.ReliableFragmentedSequenced); // Messages like this, should always be sent via the fragmented pipeline.
651661
SendMessageInstantly(sendTarget.ClientId, payload, pipeline);
652662
}
653663
}
@@ -728,10 +738,6 @@ private void SendBatchedMessageAndClearQueue(SendTarget sendTarget, SendQueue se
728738
{
729739
NetworkPipeline pipeline = sendTarget.NetworkPipeline;
730740
var payloadSize = sendQueue.Count + 1; // 1 extra byte to tell whether the message is batched or not
731-
if (payloadSize > NetworkParameterConstants.MTU) // If this is bigger than MTU then force it to be sent via the FragmentedReliableSequencedPipeline
732-
{
733-
pipeline = m_ReliableSequencedFragmentedPipeline;
734-
}
735741

736742
var sendBuffer = sendQueue.GetData();
737743
SendBatchedMessage(sendTarget.ClientId, ref sendBuffer, pipeline);
@@ -795,7 +801,10 @@ public override void Shutdown()
795801
m_ServerClientId = 0;
796802
}
797803

798-
public void CreateDriver(UnityTransport transport, out NetworkDriver driver, out NetworkPipeline unreliableSequencedPipeline, out NetworkPipeline reliableSequencedFragmentedPipeline)
804+
public void CreateDriver(UnityTransport transport, out NetworkDriver driver,
805+
out NetworkPipeline unreliableFragmentedPipeline,
806+
out NetworkPipeline unreliableSequencedFragmentedPipeline,
807+
out NetworkPipeline reliableSequencedFragmentedPipeline)
799808
{
800809
var maxFrameTimeMS = 0;
801810

@@ -817,7 +826,12 @@ public void CreateDriver(UnityTransport transport, out NetworkDriver driver, out
817826
#if UNITY_EDITOR || DEVELOPMENT_BUILD
818827
if (simulatorParams.PacketDelayMs > 0 || simulatorParams.PacketDropInterval > 0)
819828
{
820-
unreliableSequencedPipeline = driver.CreatePipeline(
829+
unreliableFragmentedPipeline = driver.CreatePipeline(
830+
typeof(FragmentationPipelineStage),
831+
typeof(SimulatorPipelineStage),
832+
typeof(SimulatorPipelineStageInSend));
833+
unreliableSequencedFragmentedPipeline = driver.CreatePipeline(
834+
typeof(FragmentationPipelineStage),
821835
typeof(UnreliableSequencedPipelineStage),
822836
typeof(SimulatorPipelineStage),
823837
typeof(SimulatorPipelineStageInSend));
@@ -830,7 +844,10 @@ public void CreateDriver(UnityTransport transport, out NetworkDriver driver, out
830844
else
831845
#endif
832846
{
833-
unreliableSequencedPipeline = driver.CreatePipeline(typeof(UnreliableSequencedPipelineStage));
847+
unreliableFragmentedPipeline = driver.CreatePipeline(
848+
typeof(FragmentationPipelineStage));
849+
unreliableSequencedFragmentedPipeline = driver.CreatePipeline(
850+
typeof(FragmentationPipelineStage), typeof(UnreliableSequencedPipelineStage));
834851
reliableSequencedFragmentedPipeline = driver.CreatePipeline(
835852
typeof(FragmentationPipelineStage), typeof(ReliableSequencedPipelineStage)
836853
);

com.unity.netcode.adapter.utp/Tests/Runtime/TransportTests.cs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ namespace Unity.Netcode.UTP.RuntimeTests
1212
{
1313
public class TransportTests
1414
{
15+
// No need to test all reliable delivery methods since they all map to the same pipeline.
16+
private static readonly NetworkDelivery[] k_DeliveryParameters =
17+
{
18+
NetworkDelivery.Unreliable,
19+
NetworkDelivery.UnreliableSequenced,
20+
NetworkDelivery.Reliable
21+
};
22+
1523
private UnityTransport m_Server, m_Client1, m_Client2;
1624
private List<TransportEvent> m_ServerEvents, m_Client1Events, m_Client2Events;
1725

@@ -46,7 +54,7 @@ public IEnumerator Cleanup()
4654

4755
// Check if can make a simple data exchange.
4856
[UnityTest]
49-
public IEnumerator PingPong()
57+
public IEnumerator PingPong([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
5058
{
5159
InitializeTransport(out m_Server, out m_ServerEvents);
5260
InitializeTransport(out m_Client1, out m_Client1Events);
@@ -57,28 +65,25 @@ public IEnumerator PingPong()
5765
yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ServerEvents);
5866

5967
var ping = new ArraySegment<byte>(Encoding.ASCII.GetBytes("ping"));
60-
m_Client1.Send(m_Client1.ServerClientId, ping, NetworkDelivery.ReliableSequenced);
68+
m_Client1.Send(m_Client1.ServerClientId, ping, delivery);
6169

6270
yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents);
6371

6472
Assert.That(m_ServerEvents[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("ping")));
6573

6674
var pong = new ArraySegment<byte>(Encoding.ASCII.GetBytes("pong"));
67-
m_Server.Send(m_ServerEvents[0].ClientID, pong, NetworkDelivery.ReliableSequenced);
75+
m_Server.Send(m_ServerEvents[0].ClientID, pong, delivery);
6876

6977
yield return WaitForNetworkEvent(NetworkEvent.Data, m_Client1Events);
7078

7179
Assert.That(m_Client1Events[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("pong")));
7280

73-
// server.Shutdown();
74-
// client.Shutdown();
75-
7681
yield return null;
7782
}
7883

7984
// Check if can make a simple data exchange (both ways at a time).
8085
[UnityTest]
81-
public IEnumerator PingPongSimultaneous()
86+
public IEnumerator PingPongSimultaneous([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
8287
{
8388
InitializeTransport(out m_Server, out m_ServerEvents);
8489
InitializeTransport(out m_Client1, out m_Client1Events);
@@ -89,8 +94,8 @@ public IEnumerator PingPongSimultaneous()
8994
yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ServerEvents);
9095

9196
var ping = new ArraySegment<byte>(Encoding.ASCII.GetBytes("ping"));
92-
m_Server.Send(m_ServerEvents[0].ClientID, ping, NetworkDelivery.ReliableSequenced);
93-
m_Client1.Send(m_Client1.ServerClientId, ping, NetworkDelivery.ReliableSequenced);
97+
m_Server.Send(m_ServerEvents[0].ClientID, ping, delivery);
98+
m_Client1.Send(m_Client1.ServerClientId, ping, delivery);
9499

95100
// Once one event is in the other should be too.
96101
yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents);
@@ -99,8 +104,8 @@ public IEnumerator PingPongSimultaneous()
99104
Assert.That(m_Client1Events[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("ping")));
100105

101106
var pong = new ArraySegment<byte>(Encoding.ASCII.GetBytes("pong"));
102-
m_Server.Send(m_ServerEvents[0].ClientID, pong, NetworkDelivery.ReliableSequenced);
103-
m_Client1.Send(m_Client1.ServerClientId, pong, NetworkDelivery.ReliableSequenced);
107+
m_Server.Send(m_ServerEvents[0].ClientID, pong, delivery);
108+
m_Client1.Send(m_Client1.ServerClientId, pong, delivery);
104109

105110
// Once one event is in the other should be too.
106111
yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents);
@@ -112,7 +117,7 @@ public IEnumerator PingPongSimultaneous()
112117
}
113118

114119
[UnityTest]
115-
public IEnumerator FilledSendQueueSingleSend()
120+
public IEnumerator FilledSendQueueSingleSend([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
116121
{
117122
InitializeTransport(out m_Server, out m_ServerEvents);
118123
InitializeTransport(out m_Client1, out m_Client1Events);
@@ -123,15 +128,15 @@ public IEnumerator FilledSendQueueSingleSend()
123128
yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ServerEvents);
124129

125130
var payload = new ArraySegment<byte>(new byte[UnityTransport.InitialBatchQueueSize]);
126-
m_Client1.Send(m_Client1.ServerClientId, payload, NetworkDelivery.ReliableFragmentedSequenced);
131+
m_Client1.Send(m_Client1.ServerClientId, payload, delivery);
127132

128133
yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents);
129134

130135
yield return null;
131136
}
132137

133138
[UnityTest]
134-
public IEnumerator FilledSendQueueMultipleSends()
139+
public IEnumerator FilledSendQueueMultipleSends([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
135140
{
136141
InitializeTransport(out m_Server, out m_ServerEvents);
137142
InitializeTransport(out m_Client1, out m_Client1Events);
@@ -149,7 +154,7 @@ public IEnumerator FilledSendQueueMultipleSends()
149154
// Without that we wouldn't fill the send queue; it would get flushed right when we
150155
// try to send the last message.
151156
var payload = new ArraySegment<byte>(new byte[1024 - 4]);
152-
m_Client1.Send(m_Client1.ServerClientId, payload, NetworkDelivery.ReliableFragmentedSequenced);
157+
m_Client1.Send(m_Client1.ServerClientId, payload, delivery);
153158
}
154159

155160
yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents);
@@ -162,7 +167,7 @@ public IEnumerator FilledSendQueueMultipleSends()
162167

163168
// Check making multiple sends to a client in a single frame.
164169
[UnityTest]
165-
public IEnumerator MultipleSendsSingleFrame()
170+
public IEnumerator MultipleSendsSingleFrame([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
166171
{
167172
InitializeTransport(out m_Server, out m_ServerEvents);
168173
InitializeTransport(out m_Client1, out m_Client1Events);
@@ -173,10 +178,10 @@ public IEnumerator MultipleSendsSingleFrame()
173178
yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ServerEvents);
174179

175180
var data1 = new ArraySegment<byte>(new byte[] { 11 });
176-
m_Client1.Send(m_Client1.ServerClientId, data1, NetworkDelivery.ReliableSequenced);
181+
m_Client1.Send(m_Client1.ServerClientId, data1, delivery);
177182

178183
var data2 = new ArraySegment<byte>(new byte[] { 22 });
179-
m_Client1.Send(m_Client1.ServerClientId, data2, NetworkDelivery.ReliableSequenced);
184+
m_Client1.Send(m_Client1.ServerClientId, data2, delivery);
180185

181186
yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents);
182187

@@ -191,7 +196,7 @@ public IEnumerator MultipleSendsSingleFrame()
191196

192197
// Check sending data to multiple clients.
193198
[UnityTest]
194-
public IEnumerator SendMultipleClients()
199+
public IEnumerator SendMultipleClients([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
195200
{
196201
InitializeTransport(out m_Server, out m_ServerEvents);
197202
InitializeTransport(out m_Client1, out m_Client1Events);
@@ -207,10 +212,10 @@ public IEnumerator SendMultipleClients()
207212
Assert.AreEqual(2, m_ServerEvents.Count);
208213

209214
var data1 = new ArraySegment<byte>(new byte[] { 11 });
210-
m_Server.Send(m_ServerEvents[0].ClientID, data1, NetworkDelivery.ReliableSequenced);
215+
m_Server.Send(m_ServerEvents[0].ClientID, data1, delivery);
211216

212217
var data2 = new ArraySegment<byte>(new byte[] { 22 });
213-
m_Server.Send(m_ServerEvents[1].ClientID, data2, NetworkDelivery.ReliableSequenced);
218+
m_Server.Send(m_ServerEvents[1].ClientID, data2, delivery);
214219

215220
// Once one has received its data, the other should have too.
216221
yield return WaitForNetworkEvent(NetworkEvent.Data, m_Client1Events);
@@ -228,7 +233,7 @@ public IEnumerator SendMultipleClients()
228233

229234
// Check receiving data from multiple clients.
230235
[UnityTest]
231-
public IEnumerator ReceiveMultipleClients()
236+
public IEnumerator ReceiveMultipleClients([ValueSource("k_DeliveryParameters")] NetworkDelivery delivery)
232237
{
233238
InitializeTransport(out m_Server, out m_ServerEvents);
234239
InitializeTransport(out m_Client1, out m_Client1Events);
@@ -244,10 +249,10 @@ public IEnumerator ReceiveMultipleClients()
244249
Assert.AreEqual(1, m_Client2Events.Count);
245250

246251
var data1 = new ArraySegment<byte>(new byte[] { 11 });
247-
m_Client1.Send(m_Client1.ServerClientId, data1, NetworkDelivery.ReliableSequenced);
252+
m_Client1.Send(m_Client1.ServerClientId, data1, delivery);
248253

249254
var data2 = new ArraySegment<byte>(new byte[] { 22 });
250-
m_Client2.Send(m_Client2.ServerClientId, data2, NetworkDelivery.ReliableSequenced);
255+
m_Client2.Send(m_Client2.ServerClientId, data2, delivery);
251256

252257
yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents);
253258

0 commit comments

Comments
 (0)