コード例 #1
0
        public void DenyGameAction(GameAction gameAction, GameAction.IParameters parameters, int actorNumber,
                                   float triggerTime)
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException($"Cannot deny {gameAction}: Server not running");
            }

            var streamWriter = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);

            streamWriter.WriteInt(Commands.GameAction);
            streamWriter.WriteInt(GameActionManager.Instance.GetID(gameAction));
            streamWriter.WriteInt(actorNumber);
            streamWriter.WriteFloat(triggerTime);
            streamWriter.WriteBool(false); // invalid
            gameAction.SerializeParameters(ref streamWriter, parameters);

            for (var i = 0; i < _connections.Length; i++)
            {
                if (_connections[i].InternalId == actorNumber)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, _connections[i]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }
        }
コード例 #2
0
        public void SendRPC(NetBehaviour netBehaviour, string methodName, object[] args)
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException($"Cannot send rpc {methodName}: Server not running");
            }

            var streamWriter = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            {
                streamWriter.WriteInt(Commands.NetObjectRPC);
                streamWriter.WriteFloat(Time);
                streamWriter.WriteInt(netBehaviour.NetObject.ID);
                streamWriter.WriteUShort(netBehaviour.NetBehaviourID);
                NetObjectManager.Instance.SerializeRPC(ref streamWriter, netBehaviour, methodName, args);

                for (var i = 0; i < _connections.Length; i++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, _connections[i]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }
        }
コード例 #3
0
ファイル: RpcQueue.cs プロジェクト: WuYPing/NetCode-FPS
        /// <summary>
        /// 把输入写入发送buffer中
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="data"></param>
        /// <exception cref="InvalidOperationException"></exception>
        public unsafe void Schedule(DynamicBuffer <OutgoingRpcDataStreamBufferComponent> buffer, TActionRequest data)
        {
            TActionSerializer serializer = default;

            // 1字节:Rpc协议头 2字节:rpcIndex
            DataStreamWriter writer =
                new DataStreamWriter(UnsafeUtility.SizeOf <TActionRequest>() + 1 + 2, Allocator.Temp);

            if (buffer.Length == 0)
            {
                writer.WriteByte((byte)NetworkStreamProtocol.Rpc);
            }
            if (!rpcTypeHashToIndex.TryGetValue(rpcType, out var rpcIndex))
            {
                throw new InvalidOperationException("Could not find RPC index for type");
            }
            writer.WriteUShort((ushort)rpcIndex);
            serializer.Serialize(ref writer, data);

            // 把DataStreamWriter内存数据Copy到Buffer中
            var prevLen = buffer.Length;

            buffer.ResizeUninitialized(buffer.Length + writer.Length);
            byte *ptr = (byte *)buffer.GetUnsafePtr();

            ptr += prevLen;
            UnsafeUtility.MemCpy(ptr, writer.AsNativeArray().GetUnsafeReadOnlyPtr(), writer.Length);
        }
コード例 #4
0
        public void ReadWritePackedUIntWithDeferred()
        {
            using (var compressionModel = new NetworkCompressionModel(Allocator.Persistent))
            {
                var  dataStream = new DataStreamWriter(300 * 4, Allocator.Temp);
                uint base_val   = 2000;
                uint count      = 277;
                var  def        = dataStream;
                dataStream.WriteInt((int)0);
                for (uint i = 0; i < count; ++i)
                {
                    dataStream.WritePackedUInt(base_val + i, compressionModel);
                }

                dataStream.Flush();
                def.WriteInt(1979);
                def = dataStream;
                dataStream.WriteInt((int)0);
                def.WriteInt(1979);
                dataStream.Flush();
                var reader = new DataStreamReader(dataStream.AsNativeArray());
                Assert.AreEqual(1979, reader.ReadInt());
                for (uint i = 0; i < count; ++i)
                {
                    var val = reader.ReadPackedUInt(compressionModel);
                    Assert.AreEqual(base_val + i, val);
                }
                Assert.AreEqual(1979, reader.ReadInt());
            }
        }
コード例 #5
0
        public void UnspawnNetObjects(NetObject[] netObjects)
        {
            if (State != ServerState.Started && State != ServerState.Debug)
            {
                throw new InvalidOperationException("Cannot unspawn NetObjects: Server not running");
            }
            foreach (NetObject netObject in netObjects)
            {
                NetObjectManager.Instance.Unspawn(netObject.ID);
            }

            if (State == ServerState.Debug)
            {
                return;
            }
            int size = 8                        // header
                       + netObjects.Length * 4; // payload
            var streamWriter = new DataStreamWriter(size, Allocator.Temp);
            {
                streamWriter.WriteInt(Commands.UnspawnNetObjects);
                streamWriter.WriteInt(netObjects.Length);
                foreach (NetObject netObject in netObjects)
                {
                    streamWriter.WriteInt(netObject.ID);
                }

                for (var i = 0; i < _connections.Length; i++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, _connections[i]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }
        }
コード例 #6
0
ファイル: SyncAnimator.cs プロジェクト: OJuergen/Netling
        private byte[] SerializeParams()
        {
            var writer = new DataStreamWriter(1000, Allocator.Temp);

            for (var i = 0; i < _animator.parameterCount; i++)
            {
                switch (_animatorControllerParameters[i].type)
                {
                case AnimatorControllerParameterType.Float:
                    writer.WriteFloat(_animator.GetFloat(_animatorControllerParameters[i].nameHash));
                    break;

                case AnimatorControllerParameterType.Int:
                    writer.WriteInt(_animator.GetInteger(_animatorControllerParameters[i].nameHash));
                    break;

                case AnimatorControllerParameterType.Bool:
                case AnimatorControllerParameterType.Trigger:
                    writer.WriteBool(_animator.GetBool(_animatorControllerParameters[i].nameHash));
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            return(writer.AsNativeArray().ToArray());
        }
コード例 #7
0
        public void ReadIntoExistingByteArray()
        {
            var byteArray = new NativeArray <byte>(100, Allocator.Temp);

            DataStreamWriter dataStream;

            dataStream = new DataStreamWriter(3, Allocator.Temp);
            {
                dataStream.WriteByte((byte)'a');
                dataStream.WriteByte((byte)'b');
                dataStream.WriteByte((byte)'c');
                var reader = new DataStreamReader(dataStream.AsNativeArray());
                reader.ReadBytes(byteArray.GetSubArray(0, dataStream.Length));
                reader = new DataStreamReader(dataStream.AsNativeArray());
                for (int i = 0; i < reader.Length; ++i)
                {
                    Assert.AreEqual(byteArray[i], reader.ReadByte());
                }
            }
        }
コード例 #8
0
        public unsafe void Schedule(DynamicBuffer <OutgoingRpcDataStreamBufferComponent> buffer,
                                    ComponentDataFromEntity <GhostComponent> ghostFromEntity, TActionRequest data)
        {
            var serializer      = default(TActionSerializer);
            var serializerState = new RpcSerializerState {
                GhostFromEntity = ghostFromEntity
            };
            var msgHeaderLen = dynamicAssemblyList ? 10 : 4;
            int maxSize      = UnsafeUtility.SizeOf <TActionRequest>() + msgHeaderLen + 1;
            int rpcIndex     = 0;

            if (!dynamicAssemblyList && !rpcTypeHashToIndex.TryGetValue(rpcType, out rpcIndex))
            {
                throw new InvalidOperationException("Could not find RPC index for type");
            }
            while (true)
            {
                DataStreamWriter writer = new DataStreamWriter(maxSize, Allocator.Temp);
                int packetHeaderLen     = 0;
                if (buffer.Length == 0)
                {
                    packetHeaderLen = 1;
                    writer.WriteByte((byte)NetworkStreamProtocol.Rpc);
                }
                if (dynamicAssemblyList)
                {
                    writer.WriteULong(rpcType);
                }
                else
                {
                    writer.WriteUShort((ushort)rpcIndex);
                }
                var lenWriter = writer;
                writer.WriteUShort((ushort)0);
                serializer.Serialize(ref writer, serializerState, data);
                if (!writer.HasFailedWrites)
                {
                    if (writer.Length - packetHeaderLen > ushort.MaxValue)
                    {
                        throw new InvalidOperationException("RPC is too large to serialize");
                    }
                    lenWriter.WriteUShort((ushort)(writer.Length - msgHeaderLen - packetHeaderLen));
                    var prevLen = buffer.Length;
                    buffer.ResizeUninitialized(buffer.Length + writer.Length);
                    byte *ptr = (byte *)buffer.GetUnsafePtr();
                    ptr += prevLen;
                    UnsafeUtility.MemCpy(ptr, writer.AsNativeArray().GetUnsafeReadOnlyPtr(), writer.Length);
                    break;
                }
                maxSize *= 2;
            }
        }
コード例 #9
0
        public void ReadWriteString()
        {
            var dataStream = new DataStreamWriter(300 * 4, Allocator.Temp);

            NativeString64 src = new NativeString64("This is a string");

            dataStream.WriteString(src);

            //Assert.AreEqual(src.LengthInBytes+2, dataStream.Length);

            var reader = new DataStreamReader(dataStream.AsNativeArray());
            var dst    = reader.ReadString();

            Assert.AreEqual(src, dst);
        }
コード例 #10
0
        public void ReadingDataFromStreamWithSliceOffset()
        {
            var dataStream = new DataStreamWriter(100, Allocator.Temp);

            dataStream.WriteByte((byte)'a');
            dataStream.WriteByte((byte)'b');
            dataStream.WriteByte((byte)'c');
            dataStream.WriteByte((byte)'d');
            dataStream.WriteByte((byte)'e');
            dataStream.WriteByte((byte)'f');
            var reader = new DataStreamReader(dataStream.AsNativeArray().GetSubArray(3, 3));

            Assert.AreEqual('d', reader.ReadByte());
            Assert.AreEqual('e', reader.ReadByte());
            Assert.AreEqual('f', reader.ReadByte());
        }
コード例 #11
0
        public void ReadWritePackedStringDelta()
        {
            var dataStream       = new DataStreamWriter(300 * 4, Allocator.Temp);
            var compressionModel = new NetworkCompressionModel(Allocator.Temp);

            NativeString64 src      = new NativeString64("This is a string");
            NativeString64 baseline = new NativeString64("This is another string");

            dataStream.WritePackedStringDelta(src, baseline, compressionModel);
            dataStream.Flush();

            //Assert.LessOrEqual(dataStream.Length, src.LengthInBytes+2);

            var reader = new DataStreamReader(dataStream.AsNativeArray());
            var dst    = reader.ReadPackedStringDelta(baseline, compressionModel);

            Assert.AreEqual(src, dst);
        }
コード例 #12
0
        public void CreateStreamWithSourceByteArray()
        {
            byte[] byteArray = new byte[100];
            byteArray[0] = (byte)'a';
            byteArray[1] = (byte)'b';
            byteArray[2] = (byte)'c';

            DataStreamWriter dataStream;

            dataStream = new DataStreamWriter(byteArray.Length, Allocator.Temp);
            dataStream.WriteBytes(new NativeArray <byte>(byteArray, Allocator.Temp));
            var reader = new DataStreamReader(dataStream.AsNativeArray());

            for (int i = 0; i < byteArray.Length; ++i)
            {
                Assert.AreEqual(byteArray[i], reader.ReadByte());
            }
        }
コード例 #13
0
        public static unsafe void SendProtocolVersion(DynamicBuffer <OutgoingRpcDataStreamBufferComponent> buffer, NetworkProtocolVersion version)
        {
            bool             dynamicAssemblyList = (version.RpcCollectionVersion == 0);
            int              msgHeaderLen        = dynamicAssemblyList ? 10 : 4;
            DataStreamWriter writer = new DataStreamWriter(UnsafeUtility.SizeOf <NetworkProtocolVersion>() + msgHeaderLen + 1, Allocator.Temp);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (buffer.Length != 0)
            {
                throw new InvalidOperationException("Protocol version must be the very first RPC sent");
            }
#endif
            writer.WriteByte((byte)NetworkStreamProtocol.Rpc);
            if (dynamicAssemblyList)
            {
                writer.WriteULong(0);
            }
            else
            {
                writer.WriteUShort(ushort.MaxValue);
            }
            var lenWriter = writer;
            writer.WriteUShort((ushort)0);
            writer.WriteInt(version.NetCodeVersion);
            writer.WriteInt(version.GameVersion);
            if (dynamicAssemblyList)
            {
                writer.WriteULong(0);
                writer.WriteULong(0);
            }
            else
            {
                writer.WriteULong(version.RpcCollectionVersion);
                writer.WriteULong(version.ComponentCollectionVersion);
            }
            lenWriter.WriteUShort((ushort)(writer.Length - msgHeaderLen - 1));
            var prevLen = buffer.Length;
            buffer.ResizeUninitialized(buffer.Length + writer.Length);
            byte *ptr = (byte *)buffer.GetUnsafePtr();
            ptr += prevLen;
            UnsafeUtility.MemCpy(ptr, writer.AsNativeArray().GetUnsafeReadOnlyPtr(), writer.Length);
        }
コード例 #14
0
        public void CreateStreamWithPartOfSourceByteArray()
        {
            byte[] byteArray =
            {
                (byte)'s', (byte)'o', (byte)'m', (byte)'e',
                (byte)' ', (byte)'d', (byte)'a', (byte)'t', (byte)'a'
            };

            DataStreamWriter dataStream;

            dataStream = new DataStreamWriter(4, Allocator.Temp);
            dataStream.WriteBytes(new NativeArray <byte>(byteArray, Allocator.Temp).GetSubArray(0, 4));
            Assert.AreEqual(dataStream.Length, 4);
            var reader = new DataStreamReader(dataStream.AsNativeArray());

            for (int i = 0; i < dataStream.Length; ++i)
            {
                Assert.AreEqual(byteArray[i], reader.ReadByte());
            }

            Assert.Throws <ArgumentOutOfRangeException>(() => { reader.ReadByte(); });
        }
コード例 #15
0
        public void CreateStreamWithPartOfSourceByteArray()
        {
            byte[] byteArray =
            {
                (byte)'s', (byte)'o', (byte)'m', (byte)'e',
                (byte)' ', (byte)'d', (byte)'a', (byte)'t', (byte)'a'
            };

            DataStreamWriter dataStream;

            dataStream = new DataStreamWriter(4, Allocator.Temp);
            dataStream.WriteBytes(new NativeArray <byte>(byteArray, Allocator.Temp).GetSubArray(0, 4));
            Assert.AreEqual(dataStream.Length, 4);
            var reader = new DataStreamReader(dataStream.AsNativeArray());

            for (int i = 0; i < dataStream.Length; ++i)
            {
                Assert.AreEqual(byteArray[i], reader.ReadByte());
            }

            LogAssert.Expect(LogType.Error, "Trying to read 1 bytes from a stream where only 0 are available");
            Assert.AreEqual(0, reader.ReadByte());
        }
コード例 #16
0
        public void SendNetObjectsUpdate()
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException("Cannot set NetObject update: Server not running");
            }

            Profiler.BeginSample("NetObject Update");
            NetObject[] netObjects = NetObjectManager.Instance.NetObjects;

            const int headerSizeInBytes = 8;
            var       streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var       objectWriter      = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var       objectIndex       = 0;

            // compose new message if objects left to send or serialize
            while (objectIndex < netObjects.Length || objectWriter.Length > 0)
            {
                // header
                streamWriter.Clear();
                streamWriter.WriteInt(Commands.UpdateNetObjects);
                DataStreamWriter objectCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // add items as long as they fit
                var objectsInMessage = 0;
                while (streamWriter.Length + objectWriter.Length <= MaxBytesPerMessage)
                {
                    if (objectWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(objectWriter.AsNativeArray());
                        objectWriter.Clear();
                        objectsInMessage++;
                    }

                    // next object. Write if dirty
                    if (objectIndex < netObjects.Length)
                    {
                        NetObject netObject = netObjects[objectIndex++];
                        if (netObject.IsDirty)
                        {
                            WriteNetObject(netObject, ref objectWriter);
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                objectCountWriter.WriteInt(objectsInMessage);

                // message complete. Send if payload exists
                if (objectsInMessage == 0)
                {
                    break;
                }
                for (var connectionIndex = 0; connectionIndex < _connections.Length; connectionIndex++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, _connections[connectionIndex]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }

            Profiler.EndSample();
        }
コード例 #17
0
        private void SendNetAssetUpdate(bool fullLoad, NativeList <NetworkConnection> connections)
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException("Cannot send NetAsset update: Server not running");
            }
            Profiler.BeginSample("NetAsset Update");

            NetAsset[] netAssets         = NetAssetManager.Instance.GetAll();
            const int  headerSizeInBytes = 8;
            var        streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var        assetWriter       = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var        assetIndex        = 0;

            // compose new message if assets left to send or serialize
            while (assetIndex < netAssets.Length || assetWriter.Length > 0)
            {
                streamWriter.Clear();

                // write header
                streamWriter.WriteInt(Commands.UpdateNetAssets);
                DataStreamWriter netAssetCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // add assets as long as they fit
                var assetsInMessage = 0;
                while (streamWriter.Length + assetWriter.Length <= MaxBytesPerMessage)
                {
                    if (assetWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(assetWriter.AsNativeArray());
                        assetWriter.Clear();
                        assetsInMessage++;
                    }

                    // next asset. Serialize if dirty
                    if (assetIndex < netAssets.Length)
                    {
                        NetAsset netAsset = netAssets[assetIndex++];
                        if (fullLoad || netAsset.IsDirty())
                        {
                            SerializeNetAsset(netAsset, ref assetWriter, fullLoad);
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                netAssetCountWriter.WriteInt(assetsInMessage);

                // message complete. Send if payload exists
                if (assetsInMessage == 0)
                {
                    break;
                }
                for (var connectionIndex = 0; connectionIndex < connections.Length; connectionIndex++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, connections[connectionIndex]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }

            Profiler.EndSample();
        }
コード例 #18
0
        private void SendSpawnMessage(NetObject[] netObjects, NativeList <NetworkConnection> connections)
        {
            if (connections.Length == 0)
            {
                return;
            }
            AssertActive();
            const int headerSizeInBytes = 8;
            var       streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var       objectWriter      = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var       objectIndex       = 0;

            // compose new message if objects left to send or copy to message stream
            while (objectIndex < netObjects.Length || objectWriter.Length > 0)
            {
                streamWriter.Clear();

                // write header
                streamWriter.WriteInt(Commands.SpawnNetObjects);
                DataStreamWriter objectCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // copy data over to message stream and write to object stream
                var objectsInMessage = 0;
                while (streamWriter.Length + objectWriter.Length <= MaxBytesPerMessage)
                {
                    if (objectWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(objectWriter.AsNativeArray());
                        objectWriter.Clear();
                        objectsInMessage++;
                    }

                    if (objectIndex < netObjects.Length)
                    {
                        NetObject netObject = netObjects[objectIndex++];
                        objectWriter.WriteInt(netObject.ID);
                        objectWriter.WriteUShort(netObject.PrefabIndex);
                        objectWriter.WriteInt(netObject.OwnerActorNumber);
                        objectWriter.WriteVector3(netObject.transform.position);
                        objectWriter.WriteQuaternion(netObject.transform.rotation);
                        objectWriter.WriteInt(netObject.gameObject.scene.buildIndex);
                        DataStreamWriter objectSizeWriter = objectWriter;
                        objectWriter.WriteInt(0);
                        int length = objectWriter.Length;
                        netObject.Serialize(ref objectWriter, true);
                        objectSizeWriter.WriteInt(objectWriter.Length - length);
                    }
                    else
                    {
                        break;
                    }
                }

                objectCountWriter.WriteInt(objectsInMessage);

                // message complete. Send if payload present
                if (objectsInMessage == 0)
                {
                    return;
                }
                for (var connectionIndex = 0; connectionIndex < connections.Length; connectionIndex++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, connections[connectionIndex]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }
        }
コード例 #19
0
ファイル: Client.cs プロジェクト: OJuergen/Netling
        public void SendBatchedNetObjectsUpdate()
        {
            if (State == ClientState.Debug)
            {
                return;
            }
            if (State != ClientState.Connected)
            {
                Debug.LogWarning($"Cannot send messages in client state {State}");
                return;
            }

            if (IsHost)
            {
                return;
            }

            NetObject[] netObjects = NetObjectManager.Instance.NetObjects;

            const int headerSizeInBytes = 8;
            var       streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var       objectWriter      = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var       objectIndex       = 0;

            // compose new message if objects left to send or serialize
            while (objectIndex < netObjects.Length || objectWriter.Length > 0)
            {
                // header
                streamWriter.Clear();
                streamWriter.WriteInt(Commands.UpdateNetObjects);
                DataStreamWriter objectCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // add items as long as they fit
                var objectsInMessage = 0;
                while (streamWriter.Length + objectWriter.Length <= MaxBytesPerMessage)
                {
                    if (objectWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(objectWriter.AsNativeArray());
                        objectWriter.Clear();
                        objectsInMessage++;
                    }

                    // next object. Write if dirty and controlled by this client
                    if (objectIndex < netObjects.Length)
                    {
                        NetObject netObject = netObjects[objectIndex++];
                        if (netObject.IsDirty && netObject.IsMine)
                        {
                            WriteNetObject(netObject, ref objectWriter);
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                objectCountWriter.WriteInt(objectsInMessage);

                // message complete. Send if payload exists
                if (objectsInMessage > 0)
                {
                    DataStreamWriter writer = _clientDriver.BeginSend(_reliablePipeline, _clientToServerConnection);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _clientDriver.EndSend(writer);
                    DataSent?.Invoke(writer.Length);
                }
            }
        }