internal void Update()
        {
            // should we still process a connected event?
            if (connectedEventPending)
            {
                connectedEventPending = false;
                NetworkClient.OnConnectedEvent?.Invoke(this);
            }

            // process internal messages so they are applied at the correct time
            while (queue.Count > 0)
            {
                // call receive on queued writer's content, return to pool
                PooledNetworkWriter writer  = queue.Dequeue();
                ArraySegment <byte> segment = writer.ToArraySegment();
                //Debug.Log("Dequeue " + BitConverter.ToString(segment.Array, segment.Offset, segment.Count));
                TransportReceive(segment, Channels.DefaultReliable);
                NetworkWriterPool.Recycle(writer);
            }

            // should we still process a disconnected event?
            if (disconnectedEventPending)
            {
                disconnectedEventPending = false;
                NetworkClient.OnDisconnectedEvent?.Invoke(this);
            }
        }
Example #2
0
        // batch as many messages as possible into writer
        // returns true if any batch was made.
        public bool MakeNextBatch(NetworkWriter writer)
        {
            // if we have no messages then there's nothing to do
            if (messages.Count == 0)
            {
                return(false);
            }

            // make sure the writer is fresh to avoid uncertain situations
            if (writer.Position != 0)
            {
                throw new ArgumentException($"MakeNextBatch needs a fresh writer!");
            }

            // do start no matter what
            do
            {
                // add next message no matter what. even if > threshold.
                // (we do allow > threshold sized messages as single batch)
                PooledNetworkWriter message = messages.Dequeue();
                ArraySegment <byte> segment = message.ToArraySegment();
                writer.WriteBytes(segment.Array, segment.Offset, segment.Count);

                // return the writer to pool
                NetworkWriterPool.Recycle(message);
            }
            // keep going as long as we have more messages,
            // AND the next one would fit into threshold.
            while (messages.Count > 0 &&
                   writer.Position + messages.Peek().Position <= threshold);

            // we had messages, so a batch was made
            return(true);
        }
        void Update()
        {
            // if server then always sync to others.
            if (isServer)
            {
                // just use OnSerialize via SetDirtyBit only sync when position
                // changed. set dirty bits 0 or 1
                SetDirtyBit(HasEitherMovedRotatedScaled() ? 1UL : 0UL);
            }

            // no 'else if' since host mode would be both
            if (isClient)
            {
                // send to server if we have local authority (and aren't the server)
                // -> only if connectionToServer has been initialized yet too
                if (!isServer && hasAuthority)
                {
                    // check only each 'syncInterval'
                    if (Time.time - lastClientSendTime >= syncInterval)
                    {
                        if (HasEitherMovedRotatedScaled())
                        {
                            // serialize
                            // local position/rotation for VR support
                            NetworkWriter writer = NetworkWriterPool.GetWriter();
                            SerializeIntoWriter(writer, targetComponent.transform.localPosition, targetComponent.transform.localRotation, compressRotation, targetComponent.transform.localScale);

                            // send to server
                            CmdClientToServerSync(writer.ToArraySegment());
                            NetworkWriterPool.Recycle(writer);
                        }
                        lastClientSendTime = Time.time;
                    }
                }

                // apply interpolation on client for all players
                // unless this client has authority over the object. could be
                // himself or another object that he was assigned authority over
                if (!hasAuthority)
                {
                    // received one yet? (initialized?)
                    if (goal != null)
                    {
                        // teleport or interpolate
                        if (NeedsTeleport())
                        {
                            // local position/rotation for VR support
                            ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale);
                        }
                        else
                        {
                            // local position/rotation for VR support
                            ApplyPositionRotationScale(InterpolatePosition(start, goal, targetComponent.transform.localPosition),
                                                       InterpolateRotation(start, goal, targetComponent.transform.localRotation),
                                                       InterpolateScale(start, goal, targetComponent.transform.localScale));
                        }
                    }
                }
            }
        }
Example #4
0
        public virtual bool ClientSend(int channelId, NetworkWriter data)
        {
            bool result = ClientSend(channelId, data.ToArray());

            NetworkWriterPool.Recycle(data);
            return(result);
        }
Example #5
0
        public virtual bool ServerSend(int connectionId, int channelId, NetworkWriter data)
        {
            bool result = ServerSend(connectionId, channelId, data.ToArray());

            NetworkWriterPool.Recycle(data);
            return(result);
        }
Example #6
0
        public static bool SendToReady <T>(NetworkIdentity identity, T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
        {
            if (LogFilter.Debug)
            {
                Debug.Log("Server.SendToReady msgType:" + typeof(T));
            }

            if (identity != null && identity.observers != null)
            {
                // pack message into byte[] once
                NetworkWriter bytes = MessagePacker.PackWriter(msg);
                bytes.recycleCount = 1;

                bool result = true;
                foreach (KeyValuePair <int, NetworkConnection> kvp in identity.observers)
                {
                    if (kvp.Value.isReady)
                    {
                        bytes.recycleCount++;
                        result &= kvp.Value.SendWriter(bytes, channelId);
                    }
                }
                NetworkWriterPool.Recycle(bytes);
                return(result);
            }
            return(false);
        }
 internal static void Update()
 {
     // local or remote connection?
     if (isLocalClient)
     {
         // process internal messages so they are applied at the correct time
         while (localClientPacketQueue.Count > 0)
         {
             BufferHolder packet = localClientPacketQueue.Dequeue();
             if (packet.writer)
             {
                 NetworkWriter writer = (NetworkWriter)packet.data;
                 OnDataReceived(writer.ToArraySegment());
                 NetworkWriterPool.Recycle(writer);
             }
             else
             {
                 OnDataReceived(new ArraySegment <byte>((byte[])packet.data));
             }
         }
     }
     else
     {
         // only update things while connected
         if (active && connectState == ConnectState.Connected)
         {
             NetworkTime.UpdateClient();
         }
     }
 }
        protected void SendRPCInternal(Type invokeClass, string rpcName, NetworkWriter writer, int channelId)
        {
            // this was in Weaver before
            if (!NetworkServer.active)
            {
                Debug.LogError("RPC Function " + rpcName + " called on Client.");
                return;
            }
            // This cannot use NetworkServer.active, as that is not specific to this object.
            if (!isServer)
            {
                Debug.LogWarning("ClientRpc " + rpcName + " called on un-spawned object: " + name);
                return;
            }

            // construct the message
            RpcMessage message = new RpcMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, rpcName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()              // segment to avoid reader allocations
            };

            NetworkServer.SendToReady(netIdentity, message, channelId);
            NetworkWriterPool.Recycle(writer);
        }
        void FixedUpdate()
        {
            if (!sendMessagesAllowed)
            {
                return;
            }

            CheckSendRate();

            for (int i = 0; i < animator.layerCount; i++)
            {
                int   stateHash;
                float normalizedTime;
                if (!CheckAnimStateChanged(out stateHash, out normalizedTime, i))
                {
                    continue;
                }

                NetworkWriter writer = NetworkWriterPool.GetWriter();
                WriteParameters(writer);

                SendAnimationMessage(stateHash, normalizedTime, i, writer.ToArray());
                NetworkWriterPool.Recycle(writer);
            }
        }
        protected void SendCommandInternal(Type invokeClass, string cmdName, NetworkWriter writer, int channelId)
        {
            // this was in Weaver before
            // NOTE: we could remove this later to allow calling Cmds on Server
            //       to avoid Wrapper functions. a lot of people requested this.
            if (!NetworkClient.active)
            {
                Debug.LogError("Command Function " + cmdName + " called on server without an active client.");
                return;
            }
            // local players can always send commands, regardless of authority, other objects must have authority.
            if (!(isLocalPlayer || hasAuthority))
            {
                Debug.LogWarning("Trying to send command for object without authority.");
                return;
            }

            if (ClientScene.readyConnection == null)
            {
                Debug.LogError("Send command attempted with no client running [client=" + connectionToServer + "].");
                return;
            }

            // construct the message
            CommandMessage message = new CommandMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, cmdName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()              // segment to avoid reader allocations
            };

            ClientScene.readyConnection.Send(message, channelId);
            NetworkWriterPool.Recycle(writer);
        }
Example #11
0
        // get next message, unpacked from batch (if any)
        // timestamp is the REMOTE time when the batch was created remotely.
        public bool GetNextMessage(out NetworkReader message, out double remoteTimeStamp)
        {
            // getting messages would be easy via
            //   <<size, message, size, message, ...>>
            // but to save A LOT of bandwidth, we use
            //   <<message, message, ...>
            // in other words, we don't know where the current message ends
            //
            // BUT: it doesn't matter!
            // -> we simply return the reader
            //    * if we have one yet
            //    * and if there's more to read
            // -> the caller can then read one message from it
            // -> when the end is reached, we retire the batch!
            //
            // for example:
            //   while (GetNextMessage(out message))
            //       ProcessMessage(message);
            //
            message = null;

            // was our reader pointed to anything yet?
            if (reader.Length == 0)
            {
                remoteTimeStamp = 0;
                return(false);
            }

            // no more data to read?
            if (reader.Remaining == 0)
            {
                // retire the batch
                PooledNetworkWriter writer = batches.Dequeue();
                NetworkWriterPool.Recycle(writer);

                // do we have another batch?
                if (batches.Count > 0)
                {
                    // point reader to the next batch.
                    // we'll return the reader below.
                    PooledNetworkWriter next = batches.Peek();
                    StartReadingBatch(next);
                }
                // otherwise there's nothing more to read
                else
                {
                    remoteTimeStamp = 0;
                    return(false);
                }
            }

            // use the current batch's remote timestamp
            // AFTER potentially moving to the next batch ABOVE!
            remoteTimeStamp = readerRemoteTimeStamp;

            // if we got here, then we have more data to read.
            message = reader;
            return(true);
        }
Example #12
0
        // send a batch. internal so we can test it.
        internal void SendBatch(int channelId, Batch batch)
        {
            // get max batch size for this channel
            int max = Transport.activeTransport.GetMaxBatchSize(channelId);

            // we need a writer to merge queued messages into a batch
            using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
            {
                // for each queued message
                while (batch.messages.Count > 0)
                {
                    // get it
                    PooledNetworkWriter message = batch.messages.Dequeue();
                    ArraySegment <byte> segment = message.ToArraySegment();

                    // IF adding to writer would end Up >= MTU then we should
                    // flush first. the goal is to always flush < MTU packets.
                    //
                    // IMPORTANT: if writer is empty and segment is > MTU
                    //            (which can happen for large max sized message)
                    //            then we would send an empty previous writer.
                    //            => don't do that.
                    //            => only send if not empty.
                    if (writer.Position > 0 &&
                        writer.Position + segment.Count >= max)
                    {
                        // flush & reset writer
                        Transport.activeTransport.ServerSend(connectionId, channelId, writer.ToArraySegment());
                        writer.SetLength(0);
                    }

                    // now add to writer in any case
                    // -> WriteBytes instead of WriteSegment because the latter
                    //    would add a size header. we want to write directly.
                    //
                    // NOTE: it's very possible that we add > MTU to writer if
                    //       message size is > MTU.
                    //       which is fine. next iteration will just flush it.
                    writer.WriteBytes(segment.Array, segment.Offset, segment.Count);

                    // return queued message to pool
                    NetworkWriterPool.Recycle(message);
                }

                // done iterating queued messages.
                // batch might still contain the last message.
                // send it.
                if (writer.Position > 0)
                {
                    Transport.activeTransport.ServerSend(connectionId, channelId, writer.ToArraySegment());
                    writer.SetLength(0);
                }
            }

            // reset send time for this channel's batch
            batch.lastSendTime = NetworkTime.time;
        }
        public bool InvokeHandler <T>(T msg) where T : IMessageBase
        {
            NetworkWriter writer = MessagePacker.PackWriter(msg);
            NetworkReader reader = NetworkReaderPool.GetPooledReader(writer.ToArraySegment());
            bool          result = InvokeHandler(MessagePacker.GetId <T>(), reader);

            NetworkReaderPool.Recycle(reader);
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
Example #14
0
        internal static byte[] PackWithAlloc <T>(T message) where T : IMessageBase
        {
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            Pack(message, writer);
            byte[] data = writer.ToArray();

            NetworkWriterPool.Recycle(writer);

            return(data);
        }
        public static byte[] Pack <T>(T message) where T : IMessageBase
        {
            var writer = NetworkWriterPool.GetWriter();

            Pack(message, writer);
            var data = writer.ToArray();

            NetworkWriterPool.Recycle(writer);

            return(data);
        }
Example #16
0
        /// <summary>
        /// This sends a network message with a message ID on the connection. This message is sent on channel zero, which by default is the reliable channel.
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message to send.</param>
        /// <param name="channelId">The transport layer channel to send on.</param>
        /// <returns></returns>
        public bool Send <T>(T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
        {
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // pack message and send allocation free
            MessagePacker.Pack(msg, writer);
            NetworkDiagnostics.OnSend(msg, channelId, writer.Position, 1);
            bool result = Send(writer.ToArraySegment(), channelId);

            NetworkWriterPool.Recycle(writer);
            return(result);
        }
        void CheckSendRate()
        {
            if (sendMessagesAllowed && syncInterval > 0 && sendTimer < Time.time)
            {
                sendTimer = Time.time + syncInterval;

                NetworkWriter writer = NetworkWriterPool.GetWriter();
                if (WriteParameters(writer))
                {
                    SendAnimationParametersMessage(writer.ToArray());
                }
                NetworkWriterPool.Recycle(writer);
            }
        }
Example #18
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg) where T : IMessageBase
        {
            // get writer from pool
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // pack and invoke
            int msgType = MessagePacker.GetId <T>();

            MessagePacker.Pack(msg, writer);
            bool result = InvokeHandler(msgType, new NetworkReader(writer.ToArraySegment()));

            // recycle writer and return
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
Example #19
0
        public static byte[] PackMessage(int msgType, MessageBase msg)
        {
            NetworkWriter packWriter = NetworkWriterPool.GetPooledWriter();

            // write message type
            packWriter.Write((short)msgType);

            // serialize message into writer
            msg.Serialize(packWriter);

            // return byte[]
            byte[] data = packWriter.ToArray();
            NetworkWriterPool.Recycle(packWriter);
            return(data);
        }
Example #20
0
        // pack message before sending
        public static byte[] Pack <T>(T message) where T : IMessageBase
        {
            NetworkWriter packWriter = NetworkWriterPool.GetPooledWriter();

            // write message type
            int msgType = GetId <T>();

            packWriter.Write((ushort)msgType);

            // serialize message into writer
            message.Serialize(packWriter);

            // return byte[]
            byte[] data = packWriter.ToArray();
            NetworkWriterPool.Recycle(packWriter);
            return(data);
        }
Example #21
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg, int channelId) where T : IMessageBase
        {
            // get writer from pool
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // if it is a value type,  just use typeof(T) to avoid boxing
            // this works because value types cannot be derived
            // if it is a reference type (for example IMessageBase),
            // ask the message for the real type
            int msgType = MessagePacker.GetId(typeof(T).IsValueType ? typeof(T) : msg.GetType());

            MessagePacker.Pack(msg, writer);
            ArraySegment <byte> segment = writer.ToArraySegment();
            bool result = InvokeHandler(msgType, new NetworkReader(segment), channelId);

            // recycle writer and return
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
Example #22
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg, int channelId) where T : IMessageBase
        {
            // get writer from pool
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // pack and invoke
            int msgType = MessagePacker.GetId(typeof(T).IsValueType ? typeof(T) : msg.GetType());

            MessagePacker.Pack(msg, writer);
            ArraySegment <byte> segment = writer.ToArraySegment();
            NetworkReader       reader  = NetworkReaderPool.GetReader(segment);
            bool result = InvokeHandler(msgType, reader, channelId);

            NetworkReaderPool.Recycle(reader);

            // recycle writer and return
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
        internal override void Update()
        {
            base.Update();

            // should we still process a connected event?
            if (connectedEventPending)
            {
                connectedEventPending = false;
                NetworkClient.OnConnectedEvent?.Invoke();
            }

            // process internal messages so they are applied at the correct time
            while (queue.Count > 0)
            {
                // call receive on queued writer's content, return to pool
                PooledNetworkWriter writer  = queue.Dequeue();
                ArraySegment <byte> message = writer.ToArraySegment();

                // OnTransportData assumes a proper batch with timestamp etc.
                // let's make a proper batch and pass it to OnTransportData.
                Batcher batcher = GetBatchForChannelId(Channels.Reliable);
                batcher.AddMessage(message);

                using (PooledNetworkWriter batchWriter = NetworkWriterPool.GetWriter())
                {
                    // make a batch with our local time (double precision)
                    if (batcher.MakeNextBatch(batchWriter, NetworkTime.localTime))
                    {
                        NetworkClient.OnTransportData(batchWriter.ToArraySegment(), Channels.Reliable);
                    }
                }

                NetworkWriterPool.Recycle(writer);
            }

            // should we still process a disconnected event?
            if (disconnectedEventPending)
            {
                disconnectedEventPending = false;
                NetworkClient.OnDisconnectedEvent?.Invoke();
            }
        }
Example #24
0
        public static byte[] PackMessage(int msgType, MessageBase msg)
        {
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            try
            {
                // write message type
                writer.WriteInt16((short)msgType);

                // serialize message into writer
                msg.Serialize(writer);

                // return byte[]
                return(writer.ToArray());
            }
            finally
            {
                NetworkWriterPool.Recycle(writer);
            }
        }
        protected void SendEventInternal(Type invokeClass, string eventName, NetworkWriter writer, int channelId)
        {
            if (!NetworkServer.active)
            {
                Debug.LogWarning("SendEvent no server?");
                return;
            }

            // construct the message
            SyncEventMessage message = new SyncEventMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, eventName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()                // segment to avoid reader allocations
            };

            NetworkServer.SendToReady(netIdentity, message, channelId);
            NetworkWriterPool.Recycle(writer);
        }
        void FixedUpdate()
        {
            if (!sendMessagesAllowed)
            {
                return;
            }

            CheckSendRate();

            if (!CheckAnimStateChanged(out int stateHash, out float normalizedTime))
            {
                return;
            }

            NetworkWriter writer = NetworkWriterPool.GetPooledWriter();

            WriteParameters(writer);

            SendAnimationMessage(stateHash, normalizedTime, writer.ToArraySegment());
            NetworkWriterPool.Recycle(writer);
        }
Example #27
0
        // pack message before sending
        public static byte[] Pack <T>(T message) where T : IMessageBase
        {
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            try
            {
                // write message type
                int msgType = GetId <T>();
                writer.WriteUInt16((ushort)msgType);

                // serialize message into writer
                message.Serialize(writer);

                // return byte[]
                return(writer.ToArray());
            }
            finally
            {
                NetworkWriterPool.Recycle(writer);
            }
        }
        protected void SendTargetRPCInternal(NetworkConnection conn, Type invokeClass, string rpcName, NetworkWriter writer, int channelId)
        {
            // this was in Weaver before
            if (!NetworkServer.active)
            {
                Debug.LogError("TargetRPC Function " + rpcName + " called on client.");
                return;
            }
            // connection parameter is optional. assign if null.
            if (conn == null)
            {
                conn = connectionToClient;
            }
            // this was in Weaver before
            if (conn is ULocalConnectionToServer)
            {
                Debug.LogError("TargetRPC Function " + rpcName + " called on connection to server");
                return;
            }
            // This cannot use NetworkServer.active, as that is not specific to this object.
            if (!isServer)
            {
                Debug.LogWarning("TargetRpc " + rpcName + " called on un-spawned object: " + name);
                return;
            }

            // construct the message
            RpcMessage message = new RpcMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, rpcName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()              // segment to avoid reader allocations
            };

            conn.Send(message, channelId);
            NetworkWriterPool.Recycle(writer);
        }
Example #29
0
 internal static void Update()
 {
     // local or remote connection?
     if (isLocalClient)
     {
         // process internal messages so they are applied at the correct time
         while (localClientPacketQueue.Count > 0)
         {
             NetworkWriter writer = localClientPacketQueue.Dequeue();
             // TODO avoid serializing and deserializng the message
             // just pass it as is
             OnDataReceived(writer.ToArraySegment(), Channels.DefaultReliable);
             NetworkWriterPool.Recycle(writer);
         }
     }
     else
     {
         // only update things while connected
         if (active && connectState == ConnectState.Connected)
         {
             NetworkTime.UpdateClient();
         }
     }
 }
 public void Dispose()
 {
     NetworkWriterPool.Recycle(this);
 }