Ejemplo n.º 1
0
        // Send stage two: serialized NetworkMessage as ArraySegment<byte>
        internal override void Send(ArraySegment <byte> segment, int channelId = Channels.Reliable)
        {
            if (segment.Count == 0)
            {
                Debug.LogError("LocalConnection.SendBytes cannot send zero bytes");
                return;
            }

            // OnTransportData assumes batching.
            // so let's make a batch with proper timestamp prefix.
            Batcher batcher = GetBatchForChannelId(channelId);

            batcher.AddMessage(segment, NetworkTime.localTime);

            // flush it to the server's OnTransportData immediately.
            // local connection to server always invokes immediately.
            using (NetworkWriterPooled writer = NetworkWriterPool.Get())
            {
                // make a batch with our local time (double precision)
                if (batcher.GetBatch(writer))
                {
                    NetworkServer.OnTransportData(connectionId, writer.ToArraySegment(), channelId);
                }
                else
                {
                    Debug.LogError("Local connection failed to make batch. This should never happen.");
                }
            }
        }
Ejemplo n.º 2
0
        // flush batched messages at the end of every Update.
        internal virtual void Update()
        {
            // go through batches for all channels
            foreach (KeyValuePair <int, Batcher> kvp in batches)
            {
                // make and send as many batches as necessary from the stored
                // messages.
                Batcher batcher = kvp.Value;
                using (NetworkWriterPooled writer = NetworkWriterPool.Get())
                {
                    // make a batch with our local time (double precision)
                    while (batcher.MakeNextBatch(writer, NetworkTime.localTime))
                    {
                        // validate packet before handing the batch to the
                        // transport. this guarantees that we always stay
                        // within transport's max message size limit.
                        // => just in case transport forgets to check it
                        // => just in case mirror miscalulated it etc.
                        ArraySegment <byte> segment = writer.ToArraySegment();
                        if (ValidatePacketSize(segment, kvp.Key))
                        {
                            // send to transport
                            SendToTransport(segment, kvp.Key);
                            //UnityEngine.Debug.Log($"sending batch of {writer.Position} bytes for channel={kvp.Key} connId={connectionId}");

                            // reset writer for each new batch
                            writer.Position = 0;
                        }
                    }
                }
            }
        }
Ejemplo n.º 3
0
        // helper function to start reading a batch.
        void StartReadingBatch(NetworkWriterPooled batch)
        {
            // point reader to it
            reader.SetBuffer(batch.ToArraySegment());

            // read remote timestamp (double)
            // -> AddBatch quarantees that we have at least 8 bytes to read
            readerRemoteTimeStamp = reader.ReadDouble();
        }
Ejemplo n.º 4
0
 public void Send <T>(T message, int channelId = Channels.Reliable)
     where T : struct, NetworkMessage
 {
     using (NetworkWriterPooled writer = NetworkWriterPool.Get())
     {
         // pack message and send allocation free
         MessagePacking.Pack(message, writer);
         NetworkDiagnostics.OnSend(message, channelId, writer.Position, 1);
         Send(writer.ToArraySegment(), channelId);
     }
 }
Ejemplo n.º 5
0
        // helper function to copy a batch to writer and return it to pool
        static void CopyAndReturn(NetworkWriterPooled batch, NetworkWriter writer)
        {
            // make sure the writer is fresh to avoid uncertain situations
            if (writer.Position != 0)
            {
                throw new ArgumentException($"GetBatch needs a fresh writer!");
            }

            // copy to the target writer
            ArraySegment <byte> segment = batch.ToArraySegment();

            writer.WriteBytes(segment.Array, segment.Offset, segment.Count);

            // return batch to pool for reuse
            NetworkWriterPool.Return(batch);
        }
Ejemplo n.º 6
0
        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
                NetworkWriterPooled 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, NetworkTime.localTime);

                using (NetworkWriterPooled batchWriter = NetworkWriterPool.Get())
                {
                    // make a batch with our local time (double precision)
                    if (batcher.GetBatch(batchWriter))
                    {
                        NetworkClient.OnTransportData(batchWriter.ToArraySegment(), Channels.Reliable);
                    }
                }

                NetworkWriterPool.Return(writer);
            }

            // should we still process a disconnected event?
            if (disconnectedEventPending)
            {
                disconnectedEventPending = false;
                NetworkClient.OnDisconnectedEvent?.Invoke();
            }
        }
Ejemplo n.º 7
0
        // batch as many messages as possible into writer
        // returns true if any batch was made.
        public bool MakeNextBatch(NetworkWriter writer, double timeStamp)
        {
            // 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!");
            }

            // write timestamp first
            // -> double precision for accuracy over long periods of time
            writer.WriteDouble(timeStamp);

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

                // return the writer to pool
                NetworkWriterPool.Return(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);
        }