diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs index 419627476..b7134ce90 100644 --- a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs @@ -147,19 +147,22 @@ async Task ReceiveRequestAsync(UdpClient udpClient) UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); - NetworkReader reader = new NetworkReader(udpReceiveResult.Buffer); + NetworkReader networkReader = NetworkReaderPool.GetReader(udpReceiveResult.Buffer); - long handshake = reader.ReadInt64(); + long handshake = networkReader.ReadInt64(); if (handshake != secretHandshake) { // message is not for us + NetworkReaderPool.Recycle(networkReader); throw new ProtocolViolationException("Invalid handshake"); } Request request = new Request(); - request.Deserialize(reader); + request.Deserialize(networkReader); ProcessClientRequest(request, udpReceiveResult.RemoteEndPoint); + + NetworkReaderPool.Recycle(networkReader); } /// @@ -330,15 +333,20 @@ async Task ReceiveGameBroadcastAsync(UdpClient udpClient) UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); - NetworkReader reader = new NetworkReader(udpReceiveResult.Buffer); + NetworkReader networkReader = NetworkReaderPool.GetReader(udpReceiveResult.Buffer); - if (reader.ReadInt64() != secretHandshake) + if (networkReader.ReadInt64() != secretHandshake) + { + NetworkReaderPool.Recycle(networkReader); return; + } Response response = new Response(); - response.Deserialize(reader); + response.Deserialize(networkReader); ProcessResponse(response, udpReceiveResult.RemoteEndPoint); + + NetworkReaderPool.Recycle(networkReader); } /// diff --git a/Assets/Mirror/Components/NetworkAnimator.cs b/Assets/Mirror/Components/NetworkAnimator.cs index eb54fd703..c536c4e0d 100644 --- a/Assets/Mirror/Components/NetworkAnimator.cs +++ b/Assets/Mirror/Components/NetworkAnimator.cs @@ -451,7 +451,10 @@ void CmdOnAnimationServerMessage(int stateHash, float normalizedTime, int layerI if (LogFilter.Debug) Debug.Log("OnAnimationMessage for netId=" + netId); // handle and broadcast - HandleAnimMsg(stateHash, normalizedTime, layerId, new NetworkReader(parameters)); + NetworkReader networkReader = NetworkReaderPool.GetReader(parameters); + HandleAnimMsg(stateHash, normalizedTime, layerId, networkReader); + NetworkReaderPool.Recycle(networkReader); + RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, parameters); } @@ -459,7 +462,10 @@ void CmdOnAnimationServerMessage(int stateHash, float normalizedTime, int layerI void CmdOnAnimationParametersServerMessage(byte[] parameters) { // handle and broadcast - HandleAnimParamsMsg(new NetworkReader(parameters)); + NetworkReader networkReader = NetworkReaderPool.GetReader(parameters); + HandleAnimParamsMsg(networkReader); + NetworkReaderPool.Recycle(networkReader); + RpcOnAnimationParametersClientMessage(parameters); } @@ -486,13 +492,17 @@ void CmdOnAnimationResetTriggerServerMessage(int hash) [ClientRpc] void RpcOnAnimationClientMessage(int stateHash, float normalizedTime, int layerId, byte[] parameters) { - HandleAnimMsg(stateHash, normalizedTime, layerId, new NetworkReader(parameters)); + NetworkReader networkReader = NetworkReaderPool.GetReader(parameters); + HandleAnimMsg(stateHash, normalizedTime, layerId, networkReader); + NetworkReaderPool.Recycle(networkReader); } [ClientRpc] void RpcOnAnimationParametersClientMessage(byte[] parameters) { - HandleAnimParamsMsg(new NetworkReader(parameters)); + NetworkReader networkReader = NetworkReaderPool.GetReader(parameters); + HandleAnimParamsMsg(networkReader); + NetworkReaderPool.Recycle(networkReader); } [ClientRpc] diff --git a/Assets/Mirror/Components/NetworkTransformBase.cs b/Assets/Mirror/Components/NetworkTransformBase.cs index dc3d87b6f..34a698d82 100644 --- a/Assets/Mirror/Components/NetworkTransformBase.cs +++ b/Assets/Mirror/Components/NetworkTransformBase.cs @@ -252,8 +252,9 @@ public override void OnDeserialize(NetworkReader reader, bool initialState) void CmdClientToServerSync(byte[] payload) { // deserialize payload - NetworkReader reader = new NetworkReader(payload); - DeserializeFromReader(reader); + NetworkReader networkReader = NetworkReaderPool.GetReader(payload); + DeserializeFromReader(networkReader); + NetworkReaderPool.Recycle(networkReader); // server-only mode does no interpolation to save computations, // but let's set the position directly diff --git a/Assets/Mirror/Runtime/ClientScene.cs b/Assets/Mirror/Runtime/ClientScene.cs index 667cd78d8..9ac86eb80 100644 --- a/Assets/Mirror/Runtime/ClientScene.cs +++ b/Assets/Mirror/Runtime/ClientScene.cs @@ -488,8 +488,9 @@ static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage msg) // (Count is 0 if there were no components) if (msg.payload.Count > 0) { - NetworkReader payloadReader = new NetworkReader(msg.payload); + NetworkReader payloadReader = NetworkReaderPool.GetReader(msg.payload); identity.OnUpdateVars(payloadReader, true); + NetworkReaderPool.Recycle(payloadReader); } NetworkIdentity.spawned[msg.netId] = identity; @@ -683,7 +684,9 @@ internal static void OnUpdateVarsMessage(UpdateVarsMessage msg) if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) { - localObject.OnUpdateVars(new NetworkReader(msg.payload), false); + NetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload); + localObject.OnUpdateVars(networkReader, false); + NetworkReaderPool.Recycle(networkReader); } else { @@ -697,7 +700,9 @@ internal static void OnRPCMessage(RpcMessage msg) if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity identity)) { - identity.HandleRPC(msg.componentIndex, msg.functionHash, new NetworkReader(msg.payload)); + NetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload); + identity.HandleRPC(msg.componentIndex, msg.functionHash, networkReader); + NetworkReaderPool.Recycle(networkReader); } } @@ -707,7 +712,9 @@ internal static void OnSyncEventMessage(SyncEventMessage msg) if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity identity)) { - identity.HandleSyncEvent(msg.componentIndex, msg.functionHash, new NetworkReader(msg.payload)); + NetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload); + identity.HandleSyncEvent(msg.componentIndex, msg.functionHash, networkReader); + NetworkReaderPool.Recycle(networkReader); } else { diff --git a/Assets/Mirror/Runtime/MessagePacker.cs b/Assets/Mirror/Runtime/MessagePacker.cs index b50aa76a1..3eef56bf4 100644 --- a/Assets/Mirror/Runtime/MessagePacker.cs +++ b/Assets/Mirror/Runtime/MessagePacker.cs @@ -89,16 +89,22 @@ public static byte[] Pack(T message) where T : IMessageBase // unpack a message we received public static T Unpack(byte[] data) where T : IMessageBase, new() { - NetworkReader reader = new NetworkReader(data); + NetworkReader networkReader = NetworkReaderPool.GetReader(data); int msgType = GetId(); - int id = reader.ReadUInt16(); + int id = networkReader.ReadUInt16(); if (id != msgType) + { + NetworkReaderPool.Recycle(networkReader); throw new FormatException("Invalid message, could not unpack " + typeof(T).FullName); + } T message = new T(); - message.Deserialize(reader); + message.Deserialize(networkReader); + + NetworkReaderPool.Recycle(networkReader); + return message; } diff --git a/Assets/Mirror/Runtime/NetworkConnection.cs b/Assets/Mirror/Runtime/NetworkConnection.cs index f9c511f0f..229261f02 100644 --- a/Assets/Mirror/Runtime/NetworkConnection.cs +++ b/Assets/Mirror/Runtime/NetworkConnection.cs @@ -325,7 +325,9 @@ public bool InvokeHandler(T msg, int channelId) where T : IMessageBase MessagePacker.Pack(msg, writer); ArraySegment segment = writer.ToArraySegment(); - bool result = InvokeHandler(msgType, new NetworkReader(segment), channelId); + NetworkReader networkReader = NetworkReaderPool.GetReader(segment); + bool result = InvokeHandler(msgType, networkReader, channelId); + NetworkReaderPool.Recycle(networkReader); // recycle writer and return NetworkWriterPool.Recycle(writer); @@ -345,14 +347,14 @@ public bool InvokeHandler(T msg, int channelId) where T : IMessageBase internal void TransportReceive(ArraySegment buffer, int channelId) { // unpack message - NetworkReader reader = new NetworkReader(buffer); - if (MessagePacker.UnpackMessage(reader, out int msgType)) + NetworkReader networkReader = NetworkReaderPool.GetReader(buffer); + if (MessagePacker.UnpackMessage(networkReader, out int msgType)) { // logging if (logNetworkMessages) Debug.Log("ConnectionRecv " + this + " msgType:" + msgType + " content:" + BitConverter.ToString(buffer.Array, buffer.Offset, buffer.Count)); // try to invoke the handler for that message - if (InvokeHandler(msgType, reader, channelId)) + if (InvokeHandler(msgType, networkReader, channelId)) { lastMessageTime = Time.time; } @@ -362,6 +364,8 @@ internal void TransportReceive(ArraySegment buffer, int channelId) Debug.LogError("Closed connection: " + this + ". Invalid message header."); Disconnect(); } + + NetworkReaderPool.Recycle(networkReader); } internal void AddOwnedObject(NetworkIdentity obj) diff --git a/Assets/Mirror/Runtime/NetworkReader.cs b/Assets/Mirror/Runtime/NetworkReader.cs index 40b7d266e..81b1f239a 100644 --- a/Assets/Mirror/Runtime/NetworkReader.cs +++ b/Assets/Mirror/Runtime/NetworkReader.cs @@ -28,7 +28,6 @@ public class NetworkReader public int Position; public int Length => buffer.Count; - public NetworkReader(byte[] bytes) { buffer = new ArraySegment(bytes); @@ -39,6 +38,20 @@ public NetworkReader(ArraySegment segment) buffer = segment; } + // SetBuffer methods mirror constructor for ReaderPool + internal void SetBuffer(byte[] bytes) + { + buffer = new ArraySegment(bytes); + Position = 0; + } + + internal void SetBuffer(ArraySegment segment) + { + buffer = segment; + Position = 0; + } + + public byte ReadByte() { if (Position + 1 > buffer.Count) diff --git a/Assets/Mirror/Runtime/NetworkReaderPool.cs b/Assets/Mirror/Runtime/NetworkReaderPool.cs new file mode 100644 index 000000000..d7b8b3682 --- /dev/null +++ b/Assets/Mirror/Runtime/NetworkReaderPool.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +namespace Mirror +{ + public static class NetworkReaderPool + { + static readonly Stack pool = new Stack(); + + public static NetworkReader GetReader(byte[] bytes) + { + if (pool.Count != 0) + { + NetworkReader reader = pool.Pop(); + // reset buffer + reader.SetBuffer(bytes); + return reader; + } + + return new NetworkReader(bytes); + } + + public static NetworkReader GetReader(ArraySegment segment) + { + if (pool.Count != 0) + { + NetworkReader reader = pool.Pop(); + // reset buffer + reader.SetBuffer(segment); + return reader; + } + + return new NetworkReader(segment); + } + + public static void Recycle(NetworkReader reader) + { + pool.Push(reader); + } + } +} diff --git a/Assets/Mirror/Runtime/NetworkReaderPool.cs.meta b/Assets/Mirror/Runtime/NetworkReaderPool.cs.meta new file mode 100644 index 000000000..a1ef25e3a --- /dev/null +++ b/Assets/Mirror/Runtime/NetworkReaderPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bacff63613ad634a98f9e4d15d29dbf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkServer.cs b/Assets/Mirror/Runtime/NetworkServer.cs index 67422a3dc..9f37a7596 100644 --- a/Assets/Mirror/Runtime/NetworkServer.cs +++ b/Assets/Mirror/Runtime/NetworkServer.cs @@ -1016,7 +1016,10 @@ static void OnCommandMessage(NetworkConnection conn, CommandMessage msg) } if (LogFilter.Debug) Debug.Log("OnCommandMessage for netId=" + msg.netId + " conn=" + conn); - identity.HandleCommand(msg.componentIndex, msg.functionHash, new NetworkReader(msg.payload)); + + NetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload); + identity.HandleCommand(msg.componentIndex, msg.functionHash, networkReader); + NetworkReaderPool.Recycle(networkReader); } internal static void SpawnObject(GameObject obj, NetworkConnection ownerConnection)