|
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