// 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); }
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(); } }
// 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); }
// 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; // do nothing if we don't have any batches. // otherwise the below queue.Dequeue() would throw an // InvalidOperationException if operating on empty queue. if (batches.Count == 0) { remoteTimeStamp = 0; return(false); } // 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 NetworkWriterPooled writer = batches.Dequeue(); NetworkWriterPool.Return(writer); // do we have another batch? if (batches.Count > 0) { // point reader to the next batch. // we'll return the reader below. NetworkWriterPooled 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); }
public void Dispose() => NetworkWriterPool.Return(this);