com.unity.netcode.gameobjects@1.5.1

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [1.5.1] - 2023-06-07

### Added

- Added support for serializing `NativeArray<>` and `NativeList<>` in `FastBufferReader`/`FastBufferWriter`, `BufferSerializer`, `NetworkVariable`, and RPCs. (To use `NativeList<>`, add `UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT` to your Scripting Define Symbols in `Project Settings > Player`) (#2375)
- The location of the automatically-created default network prefab list can now be configured (#2544)
- Added: Message size limits (max single message and max fragmented message) can now be set using NetworkManager.MaximumTransmissionUnitSize and NetworkManager.MaximumFragmentedMessageSize for transports that don't work with the default values (#2530)
- Added `NetworkObject.SpawnWithObservers` property (default is true) that when set to false will spawn a `NetworkObject` with no observers and will not be spawned on any client until `NetworkObject.NetworkShow` is invoked. (#2568)

### Fixed

- Fixed: Fixed a null reference in codegen in some projects (#2581)
- Fixed issue where the `OnClientDisconnected` client identifier was incorrect after a pending client connection was denied. (#2569)
- Fixed warning "Runtime Network Prefabs was not empty at initialization time." being erroneously logged when no runtime network prefabs had been added (#2565)
- Fixed issue where some temporary debug console logging was left in a merged PR. (#2562)
- Fixed the "Generate Default Network Prefabs List" setting not loading correctly and always reverting to being checked. (#2545)
- Fixed issue where users could not use NetworkSceneManager.VerifySceneBeforeLoading to exclude runtime generated scenes from client synchronization. (#2550)
- Fixed missing value on `NetworkListEvent` for `EventType.RemoveAt` events.  (#2542,#2543)
- Fixed issue where parenting a NetworkTransform under a transform with a scale other than Vector3.one would result in incorrect values on non-authoritative instances. (#2538)
- Fixed issue where a server would include scene migrated and then despawned NetworkObjects to a client that was being synchronized. (#2532)
- Fixed the inspector throwing exceptions when attempting to render `NetworkVariable`s of enum types. (#2529)
- Making a `NetworkVariable` with an `INetworkSerializable` type that doesn't meet the `new()` constraint will now create a compile-time error instead of an editor crash (#2528)
- Fixed Multiplayer Tools package installation docs page link on the NetworkManager popup. (#2526)
- Fixed an exception and error logging when two different objects are shown and hidden on the same frame (#2524)
- Fixed a memory leak in `UnityTransport` that occurred if `StartClient` failed. (#2518)
- Fixed issue where a client could throw an exception if abruptly disconnected from a network session with one or more spawned `NetworkObject`(s). (#2510)
- Fixed issue where invalid endpoint addresses were not being detected and returning false from NGO UnityTransport. (#2496)
- Fixed some errors that could occur if a connection is lost and the loss is detected when attempting to write to the socket. (#2495)

## Changed

- Adding network prefabs before NetworkManager initialization is now supported. (#2565)
- Connecting clients being synchronized now switch to the server's active scene before spawning and synchronizing NetworkObjects. (#2532)
- Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.4. (#2533)
- Improved performance of NetworkBehaviour initialization by replacing reflection when initializing NetworkVariables with compile-time code generation, which should help reduce hitching during additive scene loads. (#2522)
This commit is contained in:
Unity Technologies
2023-06-07 00:00:00 +00:00
parent b5abc3ff7c
commit 4d70c198bd
119 changed files with 11328 additions and 3164 deletions

View File

@@ -90,7 +90,7 @@ namespace Unity.Netcode
{
SendData = messageBuffer
};
var size = m_NetworkManager.SendMessage(ref message, networkDelivery, clientIds);
var size = m_NetworkManager.ConnectionManager.SendMessage(ref message, networkDelivery, clientIds);
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
if (size != 0)
@@ -123,7 +123,7 @@ namespace Unity.Netcode
{
SendData = messageBuffer
};
var size = m_NetworkManager.SendMessage(ref message, networkDelivery, clientId);
var size = m_NetworkManager.ConnectionManager.SendMessage(ref message, networkDelivery, clientId);
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
if (size != 0)
{
@@ -275,7 +275,7 @@ namespace Unity.Netcode
Hash = hash,
SendData = messageStream,
};
var size = m_NetworkManager.SendMessage(ref message, networkDelivery, clientId);
var size = m_NetworkManager.ConnectionManager.SendMessage(ref message, networkDelivery, clientId);
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
if (size != 0)
@@ -333,7 +333,7 @@ namespace Unity.Netcode
Hash = hash,
SendData = messageStream
};
var size = m_NetworkManager.SendMessage(ref message, networkDelivery, clientIds);
var size = m_NetworkManager.ConnectionManager.SendMessage(ref message, networkDelivery, clientIds);
// Size is zero if we were only sending the message to ourself in which case it isn't sent.
if (size != 0)

View File

@@ -0,0 +1,26 @@
namespace Unity.Netcode
{
/// <summary>
/// Default NetworkTransport Message Sender
/// <see cref="NetworkMessageManager"/>
/// </summary>
internal class DefaultMessageSender : INetworkMessageSender
{
private NetworkTransport m_NetworkTransport;
private NetworkConnectionManager m_ConnectionManager;
public DefaultMessageSender(NetworkManager manager)
{
m_NetworkTransport = manager.NetworkConfig.NetworkTransport;
m_ConnectionManager = manager.ConnectionManager;
}
public void Send(ulong clientId, NetworkDelivery delivery, FastBufferWriter batchData)
{
var sendBuffer = batchData.ToTempByteArray();
m_NetworkTransport.Send(m_ConnectionManager.ClientIdToTransportId(clientId), sendBuffer, delivery);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ea6bdd38832d9947bb21c4b35bf61d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,12 +3,12 @@ using Unity.Collections;
namespace Unity.Netcode
{
internal class DeferredMessageManager : IDeferredMessageManager
internal class DeferredMessageManager : IDeferredNetworkMessageManager
{
protected struct TriggerData
{
public FastBufferReader Reader;
public MessageHeader Header;
public NetworkMessageHeader Header;
public ulong SenderId;
public float Timestamp;
public int SerializedHeaderSize;
@@ -19,7 +19,7 @@ namespace Unity.Netcode
public NativeList<TriggerData> TriggerData;
}
protected readonly Dictionary<IDeferredMessageManager.TriggerType, Dictionary<ulong, TriggerInfo>> m_Triggers = new Dictionary<IDeferredMessageManager.TriggerType, Dictionary<ulong, TriggerInfo>>();
protected readonly Dictionary<IDeferredNetworkMessageManager.TriggerType, Dictionary<ulong, TriggerInfo>> m_Triggers = new Dictionary<IDeferredNetworkMessageManager.TriggerType, Dictionary<ulong, TriggerInfo>>();
private readonly NetworkManager m_NetworkManager;
@@ -36,7 +36,7 @@ namespace Unity.Netcode
/// There is a one second maximum lifetime of triggers to avoid memory leaks. After one second has passed
/// without the requested object ID being spawned, the triggers for it are automatically deleted.
/// </summary>
public virtual unsafe void DeferMessage(IDeferredMessageManager.TriggerType trigger, ulong key, FastBufferReader reader, ref NetworkContext context)
public virtual unsafe void DeferMessage(IDeferredNetworkMessageManager.TriggerType trigger, ulong key, FastBufferReader reader, ref NetworkContext context)
{
if (!m_Triggers.TryGetValue(trigger, out var triggers))
{
@@ -90,7 +90,7 @@ namespace Unity.Netcode
}
}
protected virtual void PurgeTrigger(IDeferredMessageManager.TriggerType triggerType, ulong key, TriggerInfo triggerInfo)
protected virtual void PurgeTrigger(IDeferredNetworkMessageManager.TriggerType triggerType, ulong key, TriggerInfo triggerInfo)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
@@ -105,7 +105,7 @@ namespace Unity.Netcode
triggerInfo.TriggerData.Dispose();
}
public virtual void ProcessTriggers(IDeferredMessageManager.TriggerType trigger, ulong key)
public virtual void ProcessTriggers(IDeferredNetworkMessageManager.TriggerType trigger, ulong key)
{
if (m_Triggers.TryGetValue(trigger, out var triggers))
{
@@ -116,7 +116,7 @@ namespace Unity.Netcode
foreach (var deferredMessage in triggerInfo.TriggerData)
{
// Reader will be disposed within HandleMessage
m_NetworkManager.MessagingSystem.HandleMessage(deferredMessage.Header, deferredMessage.Reader, deferredMessage.SenderId, deferredMessage.Timestamp, deferredMessage.SerializedHeaderSize);
m_NetworkManager.ConnectionManager.MessageManager.HandleMessage(deferredMessage.Header, deferredMessage.Reader, deferredMessage.SenderId, deferredMessage.Timestamp, deferredMessage.SerializedHeaderSize);
}
triggerInfo.TriggerData.Dispose();

View File

@@ -10,11 +10,9 @@ namespace Unity.Netcode
{
string reasonSent = Reason ?? string.Empty;
// Since we don't send a ConnectionApprovedMessage, the version for this message is encded with the message
// itself. However, note that we HAVE received a ConnectionRequestMessage, so we DO have a valid targetVersion
// on this side of things - we just have to make sure the receiving side knows what version we sent it,
// since whoever has the higher version number is responsible for versioning and they may be the one
// with the higher version number.
// Since we don't send a ConnectionApprovedMessage, the version for this message is encded with the message itself.
// However, note that we HAVE received a ConnectionRequestMessage, so we DO have a valid targetVersion on this side of things.
// We just have to make sure the receiving side knows what version we sent it, since whoever has the higher version number is responsible for versioning and they may be the one with the higher version number.
BytePacker.WriteValueBitPacked(writer, Version);
if (writer.TryBeginWrite(FastBufferWriter.GetWriteSize(reasonSent)))
@@ -24,15 +22,14 @@ namespace Unity.Netcode
else
{
writer.WriteValueSafe(string.Empty);
NetworkLog.LogWarning(
"Disconnect reason didn't fit. Disconnected without sending a reason. Consider shortening the reason string.");
NetworkLog.LogWarning("Disconnect reason didn't fit. Disconnected without sending a reason. Consider shortening the reason string.");
}
}
public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion)
{
// Since we don't get a ConnectionApprovedMessage, the version for this message is encded with the message
// itself. This will override what we got from MessagingSystem... which will always be 0 here.
// Since we don't get a ConnectionApprovedMessage, the version for this message is encded with the message itself.
// This will override what we got from MessageManager... which will always be 0 here.
ByteUnpacker.ReadValueBitPacked(reader, out receivedMessageVersion);
reader.ReadValueSafe(out Reason);
return true;
@@ -40,7 +37,7 @@ namespace Unity.Netcode
public void Handle(ref NetworkContext context)
{
((NetworkManager)context.SystemOwner).DisconnectReason = Reason;
((NetworkManager)context.SystemOwner).ConnectionManager.DisconnectReason = Reason;
}
};
}

View File

@@ -1,6 +1,6 @@
namespace Unity.Netcode
{
internal interface IDeferredMessageManager
internal interface IDeferredNetworkMessageManager
{
internal enum TriggerType
{

View File

@@ -2,14 +2,14 @@ using System.Collections.Generic;
namespace Unity.Netcode
{
internal struct ILPPMessageProvider : IMessageProvider
internal struct ILPPMessageProvider : INetworkMessageProvider
{
#pragma warning disable IDE1006 // disable naming rule violation check
// This is NOT modified by RuntimeAccessModifiersILPP right now, but is populated by ILPP.
internal static readonly List<MessagingSystem.MessageWithHandler> __network_message_types = new List<MessagingSystem.MessageWithHandler>();
internal static readonly List<NetworkMessageManager.MessageWithHandler> __network_message_types = new List<NetworkMessageManager.MessageWithHandler>();
#pragma warning restore IDE1006 // restore naming rule violation check
public List<MessagingSystem.MessageWithHandler> GetMessages()
public List<NetworkMessageManager.MessageWithHandler> GetMessages()
{
return __network_message_types;
}

View File

@@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace Unity.Netcode
{
internal interface IMessageProvider
{
List<MessagingSystem.MessageWithHandler> GetMessages();
}
}

View File

@@ -1,4 +1,3 @@
using Unity.Collections;
namespace Unity.Netcode
{

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Unity.Netcode
{
internal interface INetworkMessageProvider
{
List<NetworkMessageManager.MessageWithHandler> GetMessages();
}
}

View File

@@ -1,6 +1,6 @@
namespace Unity.Netcode
{
internal interface IMessageSender
internal interface INetworkMessageSender
{
void Send(ulong clientId, NetworkDelivery delivery, FastBufferWriter batchData);
}

View File

@@ -24,7 +24,7 @@ namespace Unity.Netcode
ByteUnpacker.ReadValueBitPacked(reader, out OwnerClientId);
if (!networkManager.SpawnManager.SpawnedObjects.ContainsKey(NetworkObjectId))
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context);
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context);
return false;
}

View File

@@ -84,18 +84,18 @@ namespace Unity.Netcode
{
var messageVersion = new MessageVersionData();
messageVersion.Deserialize(reader);
networkManager.MessagingSystem.SetVersion(context.SenderId, messageVersion.Hash, messageVersion.Version);
networkManager.ConnectionManager.MessageManager.SetVersion(context.SenderId, messageVersion.Hash, messageVersion.Version);
messageHashesInOrder[i] = messageVersion.Hash;
// Update the received version since this message will always be passed version 0, due to the map not
// being initialized until just now.
var messageType = networkManager.MessagingSystem.GetMessageForHash(messageVersion.Hash);
var messageType = networkManager.ConnectionManager.MessageManager.GetMessageForHash(messageVersion.Hash);
if (messageType == typeof(ConnectionApprovedMessage))
{
receivedMessageVersion = messageVersion.Version;
}
}
networkManager.MessagingSystem.SetServerMessageOrder(messageHashesInOrder);
networkManager.ConnectionManager.MessageManager.SetServerMessageOrder(messageHashesInOrder);
messageHashesInOrder.Dispose();
// ============================================================
// END FORBIDDEN SEGMENT
@@ -117,8 +117,11 @@ namespace Unity.Netcode
networkManager.NetworkTimeSystem.Reset(time.Time, 0.15f); // Start with a constant RTT of 150 until we receive values from the transport.
networkManager.NetworkTickSystem.Reset(networkManager.NetworkTimeSystem.LocalTime, networkManager.NetworkTimeSystem.ServerTime);
networkManager.LocalClient = new NetworkClient() { ClientId = networkManager.LocalClientId };
networkManager.IsApproved = true;
networkManager.ConnectionManager.LocalClient.SetRole(false, true, networkManager);
networkManager.ConnectionManager.LocalClient.IsApproved = true;
networkManager.ConnectionManager.LocalClient.ClientId = OwnerClientId;
// Stop the client-side approval timeout coroutine since we are approved.
networkManager.ConnectionManager.StopClientApprovalCoroutine();
// Only if scene management is disabled do we handle NetworkObject synchronization at this point
if (!networkManager.NetworkConfig.EnableSceneManagement)
@@ -138,7 +141,7 @@ namespace Unity.Netcode
// Mark the client being connected
networkManager.IsConnectedClient = true;
// When scene management is disabled we notify after everything is synchronized
networkManager.InvokeOnClientConnectedCallback(context.SenderId);
networkManager.ConnectionManager.InvokeOnClientConnectedCallback(context.SenderId);
}
}
}

View File

@@ -59,11 +59,11 @@ namespace Unity.Netcode
{
var messageVersion = new MessageVersionData();
messageVersion.Deserialize(reader);
networkManager.MessagingSystem.SetVersion(context.SenderId, messageVersion.Hash, messageVersion.Version);
networkManager.ConnectionManager.MessageManager.SetVersion(context.SenderId, messageVersion.Hash, messageVersion.Version);
// Update the received version since this message will always be passed version 0, due to the map not
// being initialized until just now.
var messageType = networkManager.MessagingSystem.GetMessageForHash(messageVersion.Hash);
var messageType = networkManager.ConnectionManager.MessageManager.GetMessageForHash(messageVersion.Hash);
if (messageType == typeof(ConnectionRequestMessage))
{
receivedMessageVersion = messageVersion.Version;
@@ -135,7 +135,7 @@ namespace Unity.Netcode
var networkManager = (NetworkManager)context.SystemOwner;
var senderId = context.SenderId;
if (networkManager.PendingClients.TryGetValue(senderId, out PendingClient client))
if (networkManager.ConnectionManager.PendingClients.TryGetValue(senderId, out PendingClient client))
{
// Set to pending approval to prevent future connection requests from being approved
client.ConnectionState = PendingClient.State.PendingApproval;
@@ -143,17 +143,8 @@ namespace Unity.Netcode
if (networkManager.NetworkConfig.ConnectionApproval)
{
// Note: Delegate creation allocates.
// Note: ToArray() also allocates. :(
var response = new NetworkManager.ConnectionApprovalResponse();
networkManager.ClientsToApprove[senderId] = response;
networkManager.ConnectionApprovalCallback(
new NetworkManager.ConnectionApprovalRequest
{
Payload = ConnectionData,
ClientNetworkId = senderId
}, response);
var messageRequest = this;
networkManager.ConnectionManager.ApproveConnection(ref messageRequest, ref context);
}
else
{
@@ -162,7 +153,7 @@ namespace Unity.Netcode
Approved = true,
CreatePlayerObject = networkManager.NetworkConfig.PlayerPrefab != null
};
networkManager.HandleConnectionApproval(senderId, response);
networkManager.ConnectionManager.HandleConnectionApproval(senderId, response);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Unity.Netcode
ObjectInfo.Deserialize(reader);
if (!networkManager.NetworkConfig.ForceSamePrefabs && !networkManager.SpawnManager.HasPrefab(ObjectInfo))
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredMessageManager.TriggerType.OnAddPrefab, ObjectInfo.Hash, reader, ref context);
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, ObjectInfo.Hash, reader, ref context);
return false;
}
m_ReceivedNetworkVariableData = reader;

View File

@@ -26,7 +26,7 @@ namespace Unity.Netcode
if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject))
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context);
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context);
return false;
}
return true;

View File

@@ -67,8 +67,8 @@ namespace Unity.Netcode
// The object containing the behaviour we're about to process is about to be shown to this client
// As a result, the client will get the fully serialized NetworkVariable and would be confused by
// an extraneous delta
if (NetworkBehaviour.NetworkManager.ObjectsToShowToClient.ContainsKey(TargetClientId) &&
NetworkBehaviour.NetworkManager.ObjectsToShowToClient[TargetClientId]
if (NetworkBehaviour.NetworkManager.SpawnManager.ObjectsToShowToClient.ContainsKey(TargetClientId) &&
NetworkBehaviour.NetworkManager.SpawnManager.ObjectsToShowToClient[TargetClientId]
.Contains(NetworkBehaviour.NetworkObject))
{
shouldWrite = false;
@@ -90,7 +90,7 @@ namespace Unity.Netcode
{
if (NetworkBehaviour.NetworkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
{
var tempWriter = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp, MessagingSystem.FRAGMENTED_MESSAGE_MAX_SIZE);
var tempWriter = new FastBufferWriter(NetworkBehaviour.NetworkManager.MessageManager.NonFragmentedMessageMaxSize, Allocator.Temp, NetworkBehaviour.NetworkManager.MessageManager.FragmentedMessageMaxSize);
NetworkBehaviour.NetworkVariableFields[i].WriteDelta(tempWriter);
BytePacker.WriteValueBitPacked(writer, tempWriter.Length);
@@ -234,7 +234,7 @@ namespace Unity.Netcode
}
else
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredMessageManager.TriggerType.OnSpawn, NetworkObjectId, m_ReceivedNetworkVariableData, ref context);
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, NetworkObjectId, m_ReceivedNetworkVariableData, ref context);
}
}
}

View File

@@ -85,7 +85,7 @@ namespace Unity.Netcode
if (!networkManager.SpawnManager.SpawnedObjects.ContainsKey(NetworkObjectId))
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context);
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context);
return false;
}
return true;

View File

@@ -23,7 +23,7 @@ namespace Unity.Netcode
var networkManager = (NetworkManager)context.SystemOwner;
if (!networkManager.SpawnManager.SpawnedObjects.ContainsKey(metadata.NetworkObjectId))
{
networkManager.DeferredMessageManager.DeferMessage(IDeferredMessageManager.TriggerType.OnSpawn, metadata.NetworkObjectId, reader, ref context);
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, metadata.NetworkObjectId, reader, ref context);
return false;
}

View File

@@ -3,7 +3,7 @@ namespace Unity.Netcode
/// <summary>
/// Header placed at the start of each message batch
/// </summary>
internal struct BatchHeader : INetworkSerializeByMemcpy
internal struct NetworkBatchHeader : INetworkSerializeByMemcpy
{
internal const ushort MagicValue = 0x1160;
/// <summary>

View File

@@ -6,7 +6,7 @@ namespace Unity.Netcode
internal ref struct NetworkContext
{
/// <summary>
/// An opaque object used to represent the owner of the MessagingSystem that's receiving the message.
/// An opaque object used to represent the owner of the NetworkMessageManager that's receiving the message.
/// Outside of testing environments, the type of this variable will be <see cref="NetworkManager"/>
/// </summary>
public object SystemOwner;
@@ -24,7 +24,7 @@ namespace Unity.Netcode
/// <summary>
/// The header data that was sent with the message
/// </summary>
public MessageHeader Header;
public NetworkMessageHeader Header;
/// <summary>
/// The actual serialized size of the header when packed into the buffer

View File

@@ -0,0 +1,119 @@
using System;
namespace Unity.Netcode
{
internal class NetworkManagerHooks : INetworkHooks
{
private NetworkManager m_NetworkManager;
internal NetworkManagerHooks(NetworkManager manager)
{
m_NetworkManager = manager;
}
public void OnBeforeSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery) where T : INetworkMessage
{
}
public void OnAfterSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery, int messageSizeBytes) where T : INetworkMessage
{
}
public void OnBeforeReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
{
}
public void OnAfterReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
{
}
public void OnBeforeSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
{
}
public void OnAfterSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
{
}
public void OnBeforeReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
{
}
public void OnAfterReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
{
}
public bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelivery delivery)
{
return !m_NetworkManager.MessageManager.StopProcessing;
}
public bool OnVerifyCanReceive(ulong senderId, Type messageType, FastBufferReader messageContent, ref NetworkContext context)
{
if (m_NetworkManager.IsServer)
{
if (messageType == typeof(ConnectionApprovedMessage))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionApprovedMessage)} was received from a client on the server side. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {NetworkMessageManager.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
if (m_NetworkManager.ConnectionManager.PendingClients.TryGetValue(senderId, out PendingClient client) && (client.ConnectionState == PendingClient.State.PendingApproval || (client.ConnectionState == PendingClient.State.PendingConnection && messageType != typeof(ConnectionRequestMessage))))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogWarning($"Message received from {nameof(senderId)}={senderId} before it has been accepted");
}
return false;
}
if (m_NetworkManager.ConnectedClients.TryGetValue(senderId, out NetworkClient connectedClient) && messageType == typeof(ConnectionRequestMessage))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionRequestMessage)} was received from a client when the connection has already been established. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {NetworkMessageManager.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
}
else
{
if (messageType == typeof(ConnectionRequestMessage))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionRequestMessage)} was received from the server on the client side. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {NetworkMessageManager.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
if (m_NetworkManager.IsConnectedClient && messageType == typeof(ConnectionApprovedMessage))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionApprovedMessage)} was received from the server when the connection has already been established. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {NetworkMessageManager.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
}
return !m_NetworkManager.MessageManager.StopProcessing;
}
public void OnBeforeHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
{
}
public void OnAfterHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c2be7fa492911d549bfca52be96c0906
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,13 +3,11 @@ namespace Unity.Netcode
/// <summary>
/// This is the header data that's serialized to the network when sending an <see cref="INetworkMessage"/>
/// </summary>
internal struct MessageHeader : INetworkSerializeByMemcpy
internal struct NetworkMessageHeader : INetworkSerializeByMemcpy
{
/// <summary>
/// The byte representation of the message type. This is automatically assigned to each message
/// by the MessagingSystem. This value is deterministic only so long as the list of messages remains
/// unchanged - if new messages are added or messages are removed, MessageType assignments may be
/// calculated differently.
/// The byte representation of the message type. This is automatically assigned to each message by the NetworkMessageManager.
/// This value is deterministic only so long as the list of messages remains unchanged - if new messages are added or messages are removed, MessageType assignments may be calculated differently.
/// </summary>
public uint MessageType;

View File

@@ -11,22 +11,34 @@ namespace Unity.Netcode
{
internal class HandlerNotRegisteredException : SystemException
{
public HandlerNotRegisteredException() { }
public HandlerNotRegisteredException(string issue) : base(issue) { }
public HandlerNotRegisteredException()
{
}
public HandlerNotRegisteredException(string issue) : base(issue)
{
}
}
internal class InvalidMessageStructureException : SystemException
{
public InvalidMessageStructureException() { }
public InvalidMessageStructureException(string issue) : base(issue) { }
public InvalidMessageStructureException()
{
}
public InvalidMessageStructureException(string issue) : base(issue)
{
}
}
internal class MessagingSystem : IDisposable
internal class NetworkMessageManager : IDisposable
{
public bool StopProcessing = false;
private struct ReceiveQueueItem
{
public FastBufferReader Reader;
public MessageHeader Header;
public NetworkMessageHeader Header;
public ulong SenderId;
public float Timestamp;
public int MessageHeaderSerializedSize;
@@ -34,7 +46,7 @@ namespace Unity.Netcode
private struct SendQueueItem
{
public BatchHeader BatchHeader;
public NetworkBatchHeader BatchHeader;
public FastBufferWriter Writer;
public readonly NetworkDelivery NetworkDelivery;
@@ -42,11 +54,12 @@ namespace Unity.Netcode
{
Writer = new FastBufferWriter(writerSize, writerAllocator, maxWriterSize);
NetworkDelivery = delivery;
BatchHeader = new BatchHeader { Magic = BatchHeader.MagicValue };
BatchHeader = new NetworkBatchHeader { Magic = NetworkBatchHeader.MagicValue };
}
}
internal delegate void MessageHandler(FastBufferReader reader, ref NetworkContext context, MessagingSystem system);
internal delegate void MessageHandler(FastBufferReader reader, ref NetworkContext context, NetworkMessageManager manager);
internal delegate int VersionGetter();
private NativeList<ReceiveQueueItem> m_IncomingMessageQueue = new NativeList<ReceiveQueueItem>(16, Allocator.Persistent);
@@ -58,6 +71,8 @@ namespace Unity.Netcode
private Dictionary<Type, uint> m_MessageTypes = new Dictionary<Type, uint>();
private Dictionary<ulong, NativeList<SendQueueItem>> m_SendQueues = new Dictionary<ulong, NativeList<SendQueueItem>>();
private HashSet<ulong> m_DisconnectedClients = new HashSet<ulong>();
// This is m_PerClientMessageVersion[clientId][messageType] = version
private Dictionary<ulong, Dictionary<Type, int>> m_PerClientMessageVersions = new Dictionary<ulong, Dictionary<Type, int>>();
private Dictionary<uint, Type> m_MessagesByHash = new Dictionary<uint, Type>();
@@ -67,7 +82,7 @@ namespace Unity.Netcode
private uint m_HighMessageType;
private object m_Owner;
private IMessageSender m_MessageSender;
private INetworkMessageSender m_Sender;
private bool m_Disposed;
internal Type[] MessageTypes => m_ReverseTypeMap;
@@ -80,8 +95,9 @@ namespace Unity.Netcode
return m_MessageTypes[t];
}
public const int NON_FRAGMENTED_MESSAGE_MAX_SIZE = 1300;
public const int FRAGMENTED_MESSAGE_MAX_SIZE = int.MaxValue;
public const int DefaultNonFragmentedMessageMaxSize = 1300;
public int NonFragmentedMessageMaxSize = DefaultNonFragmentedMessageMaxSize;
public int FragmentedMessageMaxSize = int.MaxValue;
internal struct MessageWithHandler
{
@@ -94,7 +110,7 @@ namespace Unity.Netcode
{
var prioritizedTypes = new List<MessageWithHandler>();
// first pass puts the priority message in the first indices
// First pass puts the priority message in the first indices
// Those are the messages that must be delivered in order to allow re-ordering the others later
foreach (var t in allowedTypes)
{
@@ -117,17 +133,18 @@ namespace Unity.Netcode
return prioritizedTypes;
}
public MessagingSystem(IMessageSender messageSender, object owner, IMessageProvider provider = null)
public NetworkMessageManager(INetworkMessageSender sender, object owner, INetworkMessageProvider provider = null)
{
try
{
m_MessageSender = messageSender;
m_Sender = sender;
m_Owner = owner;
if (provider == null)
{
provider = new ILPPMessageProvider();
}
var allowedTypes = provider.GetMessages();
allowedTypes.Sort((a, b) => string.CompareOrdinal(a.MessageType.FullName, b.MessageType.FullName));
@@ -144,20 +161,21 @@ namespace Unity.Netcode
}
}
public unsafe void Dispose()
public void Dispose()
{
if (m_Disposed)
{
return;
}
// Can't just iterate SendQueues or SendQueues.Keys because ClientDisconnected removes
// from the queue.
// Can't just iterate SendQueues or SendQueues.Keys because ClientDisconnected removes from the queue.
foreach (var kvp in m_SendQueues)
{
CleanupDisconnectedClient(kvp.Key);
ClientDisconnected(kvp.Key);
}
CleanupDisconnectedClients();
for (var queueIndex = 0; queueIndex < m_IncomingMessageQueue.Length; ++queueIndex)
{
// Avoid copies...
@@ -169,7 +187,7 @@ namespace Unity.Netcode
m_Disposed = true;
}
~MessagingSystem()
~NetworkMessageManager()
{
Dispose();
}
@@ -186,7 +204,7 @@ namespace Unity.Netcode
private void RegisterMessageType(MessageWithHandler messageWithHandler)
{
// if we are out of space, perform amortized linear growth
// If we are out of space, perform amortized linear growth
if (m_HighMessageType == m_MessageHandlers.Length)
{
Array.Resize(ref m_MessageHandlers, 2 * m_MessageHandlers.Length);
@@ -220,19 +238,18 @@ namespace Unity.Netcode
{
unsafe
{
fixed (byte* nativeData = data.Array)
fixed (byte* dataPtr = data.Array)
{
var batchReader =
new FastBufferReader(nativeData + data.Offset, Allocator.None, data.Count);
if (!batchReader.TryBeginRead(sizeof(BatchHeader)))
var batchReader = new FastBufferReader(dataPtr + data.Offset, Allocator.None, data.Count);
if (!batchReader.TryBeginRead(sizeof(NetworkBatchHeader)))
{
NetworkLog.LogError("Received a packet too small to contain a BatchHeader. Ignoring it.");
return;
}
batchReader.ReadValue(out BatchHeader batchHeader);
batchReader.ReadValue(out NetworkBatchHeader batchHeader);
if (batchHeader.Magic != BatchHeader.MagicValue)
if (batchHeader.Magic != NetworkBatchHeader.MagicValue)
{
NetworkLog.LogError($"Received a packet with an invalid Magic Value. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Offset: {data.Offset}, Size: {data.Count}, Full receive array: {ByteArrayToString(data.Array, 0, data.Array.Length)}");
return;
@@ -259,8 +276,7 @@ namespace Unity.Netcode
for (var messageIdx = 0; messageIdx < batchHeader.BatchCount; ++messageIdx)
{
var messageHeader = new MessageHeader();
var messageHeader = new NetworkMessageHeader();
var position = batchReader.Position;
try
{
@@ -280,19 +296,20 @@ namespace Unity.Netcode
NetworkLog.LogError("Received a message that claimed a size larger than the packet, ending early!");
return;
}
m_IncomingMessageQueue.Add(new ReceiveQueueItem
{
Header = messageHeader,
SenderId = clientId,
Timestamp = receiveTime,
// Copy the data for this message into a new FastBufferReader that owns that memory.
// We can't guarantee the memory in the ArraySegment stays valid because we don't own it,
// so we must move it to memory we do own.
// We can't guarantee the memory in the ArraySegment stays valid because we don't own it, so we must move it to memory we do own.
Reader = new FastBufferReader(batchReader.GetUnsafePtrAtCurrentPosition(), Allocator.TempJob, (int)messageHeader.MessageSize),
MessageHeaderSerializedSize = receivedHeaderSize,
});
batchReader.Seek(batchReader.Position + (int)messageHeader.MessageSize);
}
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
{
m_Hooks[hookIdx].OnAfterReceiveBatch(clientId, batchHeader.BatchCount, batchReader.Length);
@@ -320,6 +337,7 @@ namespace Unity.Netcode
{
return null;
}
return m_MessagesByHash[messageHash];
}
@@ -329,6 +347,7 @@ namespace Unity.Netcode
{
return;
}
var messageType = m_MessagesByHash[messageHash];
if (!m_PerClientMessageVersions.ContainsKey(clientId))
@@ -353,6 +372,7 @@ namespace Unity.Netcode
{
continue;
}
var messageType = m_MessagesByHash[messagesInIdOrder[i]];
var oldId = oldTypes[messageType];
var handler = oldHandlers[oldId];
@@ -363,7 +383,7 @@ namespace Unity.Netcode
}
}
public void HandleMessage(in MessageHeader header, FastBufferReader reader, ulong senderId, float timestamp, int serializedHeaderSize)
public void HandleMessage(in NetworkMessageHeader header, FastBufferReader reader, ulong senderId, float timestamp, int serializedHeaderSize)
{
using (reader)
{
@@ -372,6 +392,7 @@ namespace Unity.Netcode
Debug.LogWarning($"Received a message with invalid message type value {header.MessageType}");
return;
}
var context = new NetworkContext
{
SystemOwner = m_Owner,
@@ -391,13 +412,12 @@ namespace Unity.Netcode
var handler = m_MessageHandlers[header.MessageType];
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
{
m_Hooks[hookIdx].OnBeforeReceiveMessage(senderId, type, reader.Length + FastBufferWriter.GetWriteSize<MessageHeader>());
m_Hooks[hookIdx].OnBeforeReceiveMessage(senderId, type, reader.Length + FastBufferWriter.GetWriteSize<NetworkMessageHeader>());
}
// This will also log an exception is if the server knows about a message type the client doesn't know
// about. In this case the handler will be null. It is still an issue the user must deal with: If the
// two connecting builds know about different messages, the server should not send a message to a client
// that doesn't know about it
// This will also log an exception is if the server knows about a message type the client doesn't know about.
// In this case the handler will be null. It is still an issue the user must deal with:
// If the two connecting builds know about different messages, the server should not send a message to a client that doesn't know about it
if (handler == null)
{
Debug.LogException(new HandlerNotRegisteredException(header.MessageType.ToString()));
@@ -406,9 +426,7 @@ namespace Unity.Netcode
{
// No user-land message handler exceptions should escape the receive loop.
// If an exception is throw, the message is ignored.
// Example use case: A bad message is received that can't be deserialized and throws
// an OverflowException because it specifies a length greater than the number of bytes in it
// for some dynamic-length value.
// Example use case: A bad message is received that can't be deserialized and throws an OverflowException because it specifies a length greater than the number of bytes in it for some dynamic-length value.
try
{
handler.Invoke(reader, ref context, this);
@@ -418,15 +436,21 @@ namespace Unity.Netcode
Debug.LogException(e);
}
}
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
{
m_Hooks[hookIdx].OnAfterReceiveMessage(senderId, type, reader.Length + FastBufferWriter.GetWriteSize<MessageHeader>());
m_Hooks[hookIdx].OnAfterReceiveMessage(senderId, type, reader.Length + FastBufferWriter.GetWriteSize<NetworkMessageHeader>());
}
}
}
internal unsafe void ProcessIncomingMessageQueue()
internal void ProcessIncomingMessageQueue()
{
if (StopProcessing)
{
return;
}
for (var index = 0; index < m_IncomingMessageQueue.Length; ++index)
{
// Avoid copies...
@@ -447,21 +471,22 @@ namespace Unity.Netcode
{
return;
}
m_SendQueues[clientId] = new NativeList<SendQueueItem>(16, Allocator.Persistent);
}
internal void ClientDisconnected(ulong clientId)
{
if (!m_SendQueues.ContainsKey(clientId))
{
return;
}
CleanupDisconnectedClient(clientId);
m_SendQueues.Remove(clientId);
m_DisconnectedClients.Add(clientId);
}
private void CleanupDisconnectedClient(ulong clientId)
{
if (!m_SendQueues.ContainsKey(clientId))
{
return;
}
var queue = m_SendQueues[clientId];
for (var i = 0; i < queue.Length; ++i)
{
@@ -469,23 +494,19 @@ namespace Unity.Netcode
}
queue.Dispose();
m_SendQueues.Remove(clientId);
m_PerClientMessageVersions.Remove(clientId);
}
internal void CleanupDisconnectedClients()
{
var removeList = new NativeList<ulong>(Allocator.Temp);
foreach (var clientId in m_PerClientMessageVersions.Keys)
foreach (var clientId in m_DisconnectedClients)
{
if (!m_SendQueues.ContainsKey(clientId))
{
removeList.Add(clientId);
}
CleanupDisconnectedClient(clientId);
}
foreach (var clientId in removeList)
{
m_PerClientMessageVersions.Remove(clientId);
}
m_DisconnectedClients.Clear();
}
public static int CreateMessageAndGetVersion<T>() where T : INetworkMessage, new()
@@ -500,14 +521,15 @@ namespace Unity.Netcode
if (forReceive)
{
Debug.LogWarning($"Trying to receive {type.Name} from client {clientId} which is not in a connected state.");
}
else
{
Debug.LogWarning($"Trying to send {type.Name} to client {clientId} which is not in a connected state.");
}
return -1;
}
if (!versionMap.TryGetValue(type, out var messageVersion))
{
return -1;
@@ -516,7 +538,7 @@ namespace Unity.Netcode
return messageVersion;
}
public static void ReceiveMessage<T>(FastBufferReader reader, ref NetworkContext context, MessagingSystem system) where T : INetworkMessage, new()
public static void ReceiveMessage<T>(FastBufferReader reader, ref NetworkContext context, NetworkMessageManager manager) where T : INetworkMessage, new()
{
var message = new T();
var messageVersion = 0;
@@ -525,24 +547,25 @@ namespace Unity.Netcode
// and can't change.
if (typeof(T) != typeof(ConnectionRequestMessage) && typeof(T) != typeof(ConnectionApprovedMessage) && typeof(T) != typeof(DisconnectReasonMessage))
{
messageVersion = system.GetMessageVersion(typeof(T), context.SenderId, true);
messageVersion = manager.GetMessageVersion(typeof(T), context.SenderId, true);
if (messageVersion < 0)
{
return;
}
}
if (message.Deserialize(reader, ref context, messageVersion))
{
for (var hookIdx = 0; hookIdx < system.m_Hooks.Count; ++hookIdx)
for (var hookIdx = 0; hookIdx < manager.m_Hooks.Count; ++hookIdx)
{
system.m_Hooks[hookIdx].OnBeforeHandleMessage(ref message, ref context);
manager.m_Hooks[hookIdx].OnBeforeHandleMessage(ref message, ref context);
}
message.Handle(ref context);
for (var hookIdx = 0; hookIdx < system.m_Hooks.Count; ++hookIdx)
for (var hookIdx = 0; hookIdx < manager.m_Hooks.Count; ++hookIdx)
{
system.m_Hooks[hookIdx].OnAfterHandleMessage(ref message, ref context);
manager.m_Hooks[hookIdx].OnAfterHandleMessage(ref message, ref context);
}
}
}
@@ -574,9 +597,8 @@ namespace Unity.Netcode
for (var i = 0; i < clientIds.Count; ++i)
{
var messageVersion = 0;
// Special case because this is the message that carries the version info - thus the version info isn't
// populated yet when we get this. The first part of this message always has to be the version data
// and can't change.
// Special case because this is the message that carries the version info - thus the version info isn't populated yet when we get this.
// The first part of this message always has to be the version data and can't change.
if (typeof(TMessageType) != typeof(ConnectionRequestMessage))
{
messageVersion = GetMessageVersion(typeof(TMessageType), clientIds[i]);
@@ -594,9 +616,9 @@ namespace Unity.Netcode
sentMessageVersions.Add(messageVersion);
var maxSize = delivery == NetworkDelivery.ReliableFragmentedSequenced ? FRAGMENTED_MESSAGE_MAX_SIZE : NON_FRAGMENTED_MESSAGE_MAX_SIZE;
var maxSize = delivery == NetworkDelivery.ReliableFragmentedSequenced ? FragmentedMessageMaxSize : NonFragmentedMessageMaxSize;
using var tmpSerializer = new FastBufferWriter(NON_FRAGMENTED_MESSAGE_MAX_SIZE - FastBufferWriter.GetWriteSize<MessageHeader>(), Allocator.Temp, maxSize - FastBufferWriter.GetWriteSize<MessageHeader>());
using var tmpSerializer = new FastBufferWriter(NonFragmentedMessageMaxSize - FastBufferWriter.GetWriteSize<NetworkMessageHeader>(), Allocator.Temp, maxSize - FastBufferWriter.GetWriteSize<NetworkMessageHeader>());
message.Serialize(tmpSerializer, messageVersion);
@@ -612,9 +634,9 @@ namespace Unity.Netcode
internal unsafe int SendPreSerializedMessage<TMessageType>(in FastBufferWriter tmpSerializer, int maxSize, ref TMessageType message, NetworkDelivery delivery, in IReadOnlyList<ulong> clientIds, int messageVersionFilter)
where TMessageType : INetworkMessage
{
using var headerSerializer = new FastBufferWriter(FastBufferWriter.GetWriteSize<MessageHeader>(), Allocator.Temp);
using var headerSerializer = new FastBufferWriter(FastBufferWriter.GetWriteSize<NetworkMessageHeader>(), Allocator.Temp);
var header = new MessageHeader
var header = new NetworkMessageHeader
{
MessageSize = (uint)tmpSerializer.Length,
MessageType = m_MessageTypes[typeof(TMessageType)],
@@ -624,13 +646,16 @@ namespace Unity.Netcode
for (var i = 0; i < clientIds.Count; ++i)
{
var messageVersion = 0;
// Special case because this is the message that carries the version info - thus the version info isn't
// populated yet when we get this. The first part of this message always has to be the version data
// and can't change.
if (m_DisconnectedClients.Contains(clientIds[i]))
{
continue;
}
// Special case because this is the message that carries the version info - thus the version info isn't populated yet when we get this.
// The first part of this message always has to be the version data and can't change.
if (typeof(TMessageType) != typeof(ConnectionRequestMessage))
{
messageVersion = GetMessageVersion(typeof(TMessageType), clientIds[i]);
var messageVersion = GetMessageVersion(typeof(TMessageType), clientIds[i]);
if (messageVersion < 0)
{
// Client doesn't know this message exists, don't send it at all.
@@ -658,20 +683,16 @@ namespace Unity.Netcode
var sendQueueItem = m_SendQueues[clientId];
if (sendQueueItem.Length == 0)
{
sendQueueItem.Add(new SendQueueItem(delivery, NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.TempJob,
maxSize));
sendQueueItem.ElementAt(0).Writer.Seek(sizeof(BatchHeader));
sendQueueItem.Add(new SendQueueItem(delivery, NonFragmentedMessageMaxSize, Allocator.TempJob, maxSize));
sendQueueItem.ElementAt(0).Writer.Seek(sizeof(NetworkBatchHeader));
}
else
{
ref var lastQueueItem = ref sendQueueItem.ElementAt(sendQueueItem.Length - 1);
if (lastQueueItem.NetworkDelivery != delivery ||
lastQueueItem.Writer.MaxCapacity - lastQueueItem.Writer.Position
< tmpSerializer.Length + headerSerializer.Length)
if (lastQueueItem.NetworkDelivery != delivery || lastQueueItem.Writer.MaxCapacity - lastQueueItem.Writer.Position < tmpSerializer.Length + headerSerializer.Length)
{
sendQueueItem.Add(new SendQueueItem(delivery, NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.TempJob,
maxSize));
sendQueueItem.ElementAt(sendQueueItem.Length - 1).Writer.Seek(sizeof(BatchHeader));
sendQueueItem.Add(new SendQueueItem(delivery, NonFragmentedMessageMaxSize, Allocator.TempJob, maxSize));
sendQueueItem.ElementAt(sendQueueItem.Length - 1).Writer.Seek(sizeof(NetworkBatchHeader));
}
}
@@ -768,6 +789,11 @@ namespace Unity.Netcode
internal unsafe void ProcessSendQueues()
{
if (StopProcessing)
{
return;
}
foreach (var kvp in m_SendQueues)
{
var clientId = kvp.Key;
@@ -775,6 +801,15 @@ namespace Unity.Netcode
for (var i = 0; i < sendQueueItem.Length; ++i)
{
ref var queueItem = ref sendQueueItem.ElementAt(i);
// This is checked at every iteration because
// 1) each writer needs to be disposed, so we have to do the full loop regardless, and
// 2) the call to m_MessageSender.Send() may result in calling ClientDisconnected(), so the result of this check may change partway through iteration
if (m_DisconnectedClients.Contains(clientId))
{
queueItem.Writer.Dispose();
continue;
}
if (queueItem.BatchHeader.BatchCount == 0)
{
queueItem.Writer.Dispose();
@@ -789,9 +824,9 @@ namespace Unity.Netcode
queueItem.Writer.Seek(0);
#if UNITY_EDITOR || DEVELOPMENT_BUILD
// Skipping the Verify and sneaking the write mark in because we know it's fine.
queueItem.Writer.Handle->AllowedWriteMark = sizeof(BatchHeader);
queueItem.Writer.Handle->AllowedWriteMark = sizeof(NetworkBatchHeader);
#endif
queueItem.BatchHeader.BatchHash = XXHash.Hash64(queueItem.Writer.GetUnsafePtr() + sizeof(BatchHeader), queueItem.Writer.Length - sizeof(BatchHeader));
queueItem.BatchHeader.BatchHash = XXHash.Hash64(queueItem.Writer.GetUnsafePtr() + sizeof(NetworkBatchHeader), queueItem.Writer.Length - sizeof(NetworkBatchHeader));
queueItem.BatchHeader.BatchSize = queueItem.Writer.Length;
@@ -800,7 +835,7 @@ namespace Unity.Netcode
try
{
m_MessageSender.Send(clientId, queueItem.NetworkDelivery, queueItem.Writer);
m_Sender.Send(clientId, queueItem.NetworkDelivery, queueItem.Writer);
for (var hookIdx = 0; hookIdx < m_Hooks.Count; ++hookIdx)
{
@@ -812,6 +847,7 @@ namespace Unity.Netcode
queueItem.Writer.Dispose();
}
}
sendQueueItem.Clear();
}
}