|
10 | 10 | using UnityEngine;
|
11 | 11 | using NetcodeNetworkEvent = Unity.Netcode.NetworkEvent;
|
12 | 12 | using TransportNetworkEvent = Unity.Networking.Transport.NetworkEvent;
|
| 13 | +using Unity.Burst; |
13 | 14 | using Unity.Collections.LowLevel.Unsafe;
|
14 | 15 | using Unity.Collections;
|
| 16 | +using Unity.Jobs; |
15 | 17 | using Unity.Networking.Transport;
|
16 | 18 | using Unity.Networking.Transport.Relay;
|
17 | 19 | using Unity.Networking.Transport.Utilities;
|
@@ -51,50 +53,48 @@ void CreateDriver(
|
51 | 53 | /// </summary>
|
52 | 54 | public static class ErrorUtilities
|
53 | 55 | {
|
54 |
| - private const string k_NetworkSuccess = "Success"; |
55 |
| - private const string k_NetworkIdMismatch = "NetworkId is invalid, likely caused by stale connection {0}."; |
56 |
| - private const string k_NetworkVersionMismatch = "NetworkVersion is invalid, likely caused by stale connection {0}."; |
57 |
| - private const string k_NetworkStateMismatch = "Sending data while connecting on connection {0} is not allowed."; |
58 |
| - private const string k_NetworkPacketOverflow = "Unable to allocate packet due to buffer overflow."; |
59 |
| - private const string k_NetworkSendQueueFull = "Currently unable to queue packet as there is too many in-flight packets. This could be because the send queue size ('Max Send Queue Size') is too small."; |
60 |
| - private const string k_NetworkHeaderInvalid = "Invalid Unity Transport Protocol header."; |
61 |
| - private const string k_NetworkDriverParallelForErr = "The parallel network driver needs to process a single unique connection per job, processing a single connection multiple times in a parallel for is not supported."; |
62 |
| - private const string k_NetworkSendHandleInvalid = "Invalid NetworkInterface Send Handle. Likely caused by pipeline send data corruption."; |
63 |
| - private const string k_NetworkArgumentMismatch = "Invalid NetworkEndpoint Arguments."; |
| 56 | + private static readonly FixedString128Bytes k_NetworkSuccess = "Success"; |
| 57 | + private static readonly FixedString128Bytes k_NetworkIdMismatch = "Invalid connection ID {0}."; |
| 58 | + private static readonly FixedString128Bytes k_NetworkVersionMismatch = "Connection ID is invalid. Likely caused by sending on stale connection {0}."; |
| 59 | + private static readonly FixedString128Bytes k_NetworkStateMismatch = "Connection state is invalid. Likely caused by sending on connection {0} which is stale or still connecting."; |
| 60 | + private static readonly FixedString128Bytes k_NetworkPacketOverflow = "Packet is too large to be allocated by the transport."; |
| 61 | + private static readonly FixedString128Bytes k_NetworkSendQueueFull = "Unable to queue packet in the transport. Likely caused by send queue size ('Max Send Queue Size') being too small."; |
64 | 62 |
|
65 | 63 | /// <summary>
|
66 |
| - /// Convert error code to human readable error message. |
| 64 | + /// Convert a UTP error code to human-readable error message. |
67 | 65 | /// </summary>
|
68 |
| - /// <param name="error">Status code of the error</param> |
69 |
| - /// <param name="connectionId">Subject connection ID of the error</param> |
70 |
| - /// <returns>Human readable error message.</returns> |
| 66 | + /// <param name="error">UTP error code.</param> |
| 67 | + /// <param name="connectionId">ID of the connection on which the error occurred.</param> |
| 68 | + /// <returns>Human-readable error message.</returns> |
71 | 69 | public static string ErrorToString(Networking.Transport.Error.StatusCode error, ulong connectionId)
|
72 | 70 | {
|
73 |
| - switch (error) |
| 71 | + return ErrorToString((int)error, connectionId); |
| 72 | + } |
| 73 | + |
| 74 | + internal static string ErrorToString(int error, ulong connectionId) |
| 75 | + { |
| 76 | + return ErrorToFixedString(error, connectionId).ToString(); |
| 77 | + } |
| 78 | + |
| 79 | + internal static FixedString128Bytes ErrorToFixedString(int error, ulong connectionId) |
| 80 | + { |
| 81 | + switch ((Networking.Transport.Error.StatusCode)error) |
74 | 82 | {
|
75 | 83 | case Networking.Transport.Error.StatusCode.Success:
|
76 | 84 | return k_NetworkSuccess;
|
77 | 85 | case Networking.Transport.Error.StatusCode.NetworkIdMismatch:
|
78 |
| - return string.Format(k_NetworkIdMismatch, connectionId); |
| 86 | + return FixedString.Format(k_NetworkIdMismatch, connectionId); |
79 | 87 | case Networking.Transport.Error.StatusCode.NetworkVersionMismatch:
|
80 |
| - return string.Format(k_NetworkVersionMismatch, connectionId); |
| 88 | + return FixedString.Format(k_NetworkVersionMismatch, connectionId); |
81 | 89 | case Networking.Transport.Error.StatusCode.NetworkStateMismatch:
|
82 |
| - return string.Format(k_NetworkStateMismatch, connectionId); |
| 90 | + return FixedString.Format(k_NetworkStateMismatch, connectionId); |
83 | 91 | case Networking.Transport.Error.StatusCode.NetworkPacketOverflow:
|
84 | 92 | return k_NetworkPacketOverflow;
|
85 | 93 | case Networking.Transport.Error.StatusCode.NetworkSendQueueFull:
|
86 | 94 | return k_NetworkSendQueueFull;
|
87 |
| - case Networking.Transport.Error.StatusCode.NetworkHeaderInvalid: |
88 |
| - return k_NetworkHeaderInvalid; |
89 |
| - case Networking.Transport.Error.StatusCode.NetworkDriverParallelForErr: |
90 |
| - return k_NetworkDriverParallelForErr; |
91 |
| - case Networking.Transport.Error.StatusCode.NetworkSendHandleInvalid: |
92 |
| - return k_NetworkSendHandleInvalid; |
93 |
| - case Networking.Transport.Error.StatusCode.NetworkArgumentMismatch: |
94 |
| - return k_NetworkArgumentMismatch; |
| 95 | + default: |
| 96 | + return FixedString.Format("Unknown error code {0}.", error); |
95 | 97 | }
|
96 |
| - |
97 |
| - return $"Unknown ErrorCode {Enum.GetName(typeof(Networking.Transport.Error.StatusCode), error)}"; |
98 | 98 | }
|
99 | 99 | }
|
100 | 100 |
|
@@ -676,55 +676,74 @@ private bool StartRelayServer()
|
676 | 676 | }
|
677 | 677 | }
|
678 | 678 |
|
679 |
| - // Send as many batched messages from the queue as possible. |
680 |
| - private void SendBatchedMessages(SendTarget sendTarget, BatchedSendQueue queue) |
| 679 | + [BurstCompile] |
| 680 | + private struct SendBatchedMessagesJob : IJob |
681 | 681 | {
|
682 |
| - var clientId = sendTarget.ClientId; |
683 |
| - var connection = ParseClientId(clientId); |
684 |
| - var pipeline = sendTarget.NetworkPipeline; |
| 682 | + public NetworkDriver.Concurrent Driver; |
| 683 | + public SendTarget Target; |
| 684 | + public BatchedSendQueue Queue; |
| 685 | + public NetworkPipeline ReliablePipeline; |
685 | 686 |
|
686 |
| - while (!queue.IsEmpty) |
| 687 | + public void Execute() |
687 | 688 | {
|
688 |
| - var result = m_Driver.BeginSend(pipeline, connection, out var writer); |
689 |
| - if (result != (int)Networking.Transport.Error.StatusCode.Success) |
| 689 | + var clientId = Target.ClientId; |
| 690 | + var connection = ParseClientId(clientId); |
| 691 | + var pipeline = Target.NetworkPipeline; |
| 692 | + |
| 693 | + while (!Queue.IsEmpty) |
690 | 694 | {
|
691 |
| - Debug.LogError("Error sending the message: " + |
692 |
| - ErrorUtilities.ErrorToString((Networking.Transport.Error.StatusCode)result, clientId)); |
693 |
| - return; |
694 |
| - } |
| 695 | + var result = Driver.BeginSend(pipeline, connection, out var writer); |
| 696 | + if (result != (int)Networking.Transport.Error.StatusCode.Success) |
| 697 | + { |
| 698 | + Debug.LogError($"Error sending message: {ErrorUtilities.ErrorToFixedString(result, clientId)}"); |
| 699 | + return; |
| 700 | + } |
695 | 701 |
|
696 |
| - // We don't attempt to send entire payloads over the reliable pipeline. Instead we |
697 |
| - // fragment it manually. This is safe and easy to do since the reliable pipeline |
698 |
| - // basically implements a stream, so as long as we separate the different messages |
699 |
| - // in the stream (the send queue does that automatically) we are sure they'll be |
700 |
| - // reassembled properly at the other end. This allows us to lift the limit of ~44KB |
701 |
| - // on reliable payloads (because of the reliable window size). |
702 |
| - var written = pipeline == m_ReliableSequencedPipeline ? queue.FillWriterWithBytes(ref writer) : queue.FillWriterWithMessages(ref writer); |
| 702 | + // We don't attempt to send entire payloads over the reliable pipeline. Instead we |
| 703 | + // fragment it manually. This is safe and easy to do since the reliable pipeline |
| 704 | + // basically implements a stream, so as long as we separate the different messages |
| 705 | + // in the stream (the send queue does that automatically) we are sure they'll be |
| 706 | + // reassembled properly at the other end. This allows us to lift the limit of ~44KB |
| 707 | + // on reliable payloads (because of the reliable window size). |
| 708 | + var written = pipeline == ReliablePipeline ? Queue.FillWriterWithBytes(ref writer) : Queue.FillWriterWithMessages(ref writer); |
703 | 709 |
|
704 |
| - result = m_Driver.EndSend(writer); |
705 |
| - if (result == written) |
706 |
| - { |
707 |
| - // Batched message was sent successfully. Remove it from the queue. |
708 |
| - queue.Consume(written); |
709 |
| - } |
710 |
| - else |
711 |
| - { |
712 |
| - // Some error occured. If it's just the UTP queue being full, then don't log |
713 |
| - // anything since that's okay (the unsent message(s) are still in the queue |
714 |
| - // and we'll retry sending the later). Otherwise log the error and remove the |
715 |
| - // message from the queue (we don't want to resend it again since we'll likely |
716 |
| - // just get the same error again). |
717 |
| - if (result != (int)Networking.Transport.Error.StatusCode.NetworkSendQueueFull) |
| 710 | + result = Driver.EndSend(writer); |
| 711 | + if (result == written) |
718 | 712 | {
|
719 |
| - Debug.LogError("Error sending the message: " + ErrorUtilities.ErrorToString((Networking.Transport.Error.StatusCode)result, clientId)); |
720 |
| - queue.Consume(written); |
| 713 | + // Batched message was sent successfully. Remove it from the queue. |
| 714 | + Queue.Consume(written); |
721 | 715 | }
|
| 716 | + else |
| 717 | + { |
| 718 | + // Some error occured. If it's just the UTP queue being full, then don't log |
| 719 | + // anything since that's okay (the unsent message(s) are still in the queue |
| 720 | + // and we'll retry sending them later). Otherwise log the error and remove the |
| 721 | + // message from the queue (we don't want to resend it again since we'll likely |
| 722 | + // just get the same error again). |
| 723 | + if (result != (int)Networking.Transport.Error.StatusCode.NetworkSendQueueFull) |
| 724 | + { |
| 725 | + Debug.LogError($"Error sending the message: {ErrorUtilities.ErrorToFixedString(result, clientId)}"); |
| 726 | + Queue.Consume(written); |
| 727 | + } |
722 | 728 |
|
723 |
| - return; |
| 729 | + return; |
| 730 | + } |
724 | 731 | }
|
725 | 732 | }
|
726 | 733 | }
|
727 | 734 |
|
| 735 | + // Send as many batched messages from the queue as possible. |
| 736 | + private void SendBatchedMessages(SendTarget sendTarget, BatchedSendQueue queue) |
| 737 | + { |
| 738 | + new SendBatchedMessagesJob |
| 739 | + { |
| 740 | + Driver = m_Driver.ToConcurrent(), |
| 741 | + Target = sendTarget, |
| 742 | + Queue = queue, |
| 743 | + ReliablePipeline = m_ReliableSequencedPipeline |
| 744 | + }.Run(); |
| 745 | + } |
| 746 | + |
728 | 747 | private bool AcceptConnection()
|
729 | 748 | {
|
730 | 749 | var connection = m_Driver.Accept();
|
|
0 commit comments