diff --git a/com.unity.netcode.adapter.utp/CHANGELOG.md b/com.unity.netcode.adapter.utp/CHANGELOG.md index 7b70104bbd..6d52b1a24d 100644 --- a/com.unity.netcode.adapter.utp/CHANGELOG.md +++ b/com.unity.netcode.adapter.utp/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +## [1.0.0-pre.3] - 2021-10-22 + +### Changed + +- Updated Unity Transport package to 1.0.0-pre.7 + +### Fixed + +- Fixed sends failing when send queue is filled or close to be filled. + ## [1.0.0-pre.2] - 2020-12-20 ### Changed diff --git a/com.unity.netcode.adapter.utp/Runtime/UnityTransport.cs b/com.unity.netcode.adapter.utp/Runtime/UnityTransport.cs index 381327941c..eccdfb77d6 100644 --- a/com.unity.netcode.adapter.utp/Runtime/UnityTransport.cs +++ b/com.unity.netcode.adapter.utp/Runtime/UnityTransport.cs @@ -563,10 +563,13 @@ public override void Initialize() m_NetworkParameters = new List(); - // If we want to be able to actually handle messages MaximumMessageLength bytes in - // size, we need to allow a bit more than that in FragmentationUtility since this needs - // to account for headers and such. 128 bytes is plenty enough for such overhead. - m_NetworkParameters.Add(new FragmentationUtility.Parameters() { PayloadCapacity = m_SendQueueBatchSize }); + // If the user sends a message of exactly m_SendQueueBatchSize length, we'll need an + // extra byte to mark it as non-batched and 4 bytes for its length. If the user fills + // up the send queue to its capacity (batched messages total m_SendQueueBatchSize), we + // still need one extra byte to mark the payload as batched. + var fragmentationCapacity = m_SendQueueBatchSize + 1 + 4; + m_NetworkParameters.Add(new FragmentationUtility.Parameters() { PayloadCapacity = fragmentationCapacity }); + m_NetworkParameters.Add(new BaselibNetworkParameter() { maximumPayloadSize = (uint)m_MaximumPacketSize, @@ -596,24 +599,22 @@ public override void Send(ulong clientId, ArraySegment payload, NetworkDel } var success = queue.AddEvent(payload); - if (!success) // This would be false only when the SendQueue is full already or we are sending a super large message at once + if (!success) // No more room in the send queue for the message. { - // If we are in here data exceeded remaining queue size. This should not happen under normal operation. - if (payload.Count > queue.Size) + // Flushing the send queue ensures we preserve the order of sends. + SendBatchedMessageAndClearQueue(sendTarget, queue); + Debug.Assert(queue.IsEmpty() == true); + queue.Clear(); + + // Try add the message to the queue as there might be enough room now that it's empty. + success = queue.AddEvent(payload); + if (!success) // Message is too large to fit in the queue. Shouldn't happen under normal operation. { // If data is too large to be batched, flush it out immediately. This happens with large initial spawn packets from Netcode for Gameobjects. - Debug.LogWarning($"Sent {payload.Count} bytes based on delivery method: {networkDelivery}. Event size exceeds sendQueueBatchSize: ({m_SendQueueBatchSize}). This can be the initial payload!"); + 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!"); Debug.Assert(networkDelivery == NetworkDelivery.ReliableFragmentedSequenced); // Messages like this, should always be sent via the fragmented pipeline. SendMessageInstantly(sendTarget.ClientId, payload, pipeline); } - else - { - // Since our queue buffer is full then send that right away, clear it and queue this new data - SendBatchedMessageAndClearQueue(sendTarget, queue); - Debug.Assert(queue.IsEmpty() == true); - queue.Clear(); - queue.AddEvent(payload); - } } } diff --git a/com.unity.netcode.adapter.utp/Tests/Runtime/TransportTests.cs b/com.unity.netcode.adapter.utp/Tests/Runtime/TransportTests.cs index 0b1789d1e7..d685ce6983 100644 --- a/com.unity.netcode.adapter.utp/Tests/Runtime/TransportTests.cs +++ b/com.unity.netcode.adapter.utp/Tests/Runtime/TransportTests.cs @@ -76,8 +76,6 @@ public IEnumerator PingPong() yield return null; } - - // Check if can make a simple data exchange (both ways at a time). [UnityTest] public IEnumerator PingPongSimultaneous() @@ -113,6 +111,55 @@ public IEnumerator PingPongSimultaneous() yield return null; } + [UnityTest] + public IEnumerator FilledSendQueueSingleSend() + { + InitializeTransport(out m_Server, out m_ServerEvents); + InitializeTransport(out m_Client1, out m_Client1Events); + + m_Server.StartServer(); + m_Client1.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ServerEvents); + + var payload = new ArraySegment(new byte[UnityTransport.InitialBatchQueueSize]); + m_Client1.Send(m_Client1.ServerClientId, payload, NetworkDelivery.ReliableFragmentedSequenced); + + yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents); + + yield return null; + } + + [UnityTest] + public IEnumerator FilledSendQueueMultipleSends() + { + InitializeTransport(out m_Server, out m_ServerEvents); + InitializeTransport(out m_Client1, out m_Client1Events); + + m_Server.StartServer(); + m_Client1.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ServerEvents); + + var numSends = UnityTransport.InitialBatchQueueSize / 1024; + + for (int i = 0; i < numSends; i++) + { + // We remove 4 bytes because each send carries a 4 bytes overhead in the send queue. + // Without that we wouldn't fill the send queue; it would get flushed right when we + // try to send the last message. + var payload = new ArraySegment(new byte[1024 - 4]); + m_Client1.Send(m_Client1.ServerClientId, payload, NetworkDelivery.ReliableFragmentedSequenced); + } + + yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents); + + // Extra event is for the Connect event. + Assert.AreEqual(numSends + 1, m_ServerEvents.Count); + + yield return null; + } + // Check making multiple sends to a client in a single frame. [UnityTest] public IEnumerator MultipleSendsSingleFrame() diff --git a/com.unity.netcode.adapter.utp/package.json b/com.unity.netcode.adapter.utp/package.json index fb24c6e651..ecadbbf753 100644 --- a/com.unity.netcode.adapter.utp/package.json +++ b/com.unity.netcode.adapter.utp/package.json @@ -6,6 +6,6 @@ "unity": "2020.3", "dependencies": { "com.unity.netcode.gameobjects": "1.0.0-pre.2", - "com.unity.transport": "1.0.0-pre.6" + "com.unity.transport": "1.0.0-pre.7" } }