private void SendPlayerUpdate() { if (!_canSendPackets) { if (_sendStopwatch.IsRunning) { _sendStopwatch.Reset(); } return; } if (!_sendStopwatch.IsRunning) { _sendStopwatch.Start(); } if (_sendStopwatch.ElapsedMilliseconds < _currentSendRate) { // TODO: maybe let the thread sleep here? return; } _sendStopwatch.Reset(); _sendStopwatch.Start(); Packet.Packet packet; lock (_currentUpdatePacket) { _currentUpdatePacket.SequenceNumber = _sequenceNumber; packet = _currentUpdatePacket.CreatePacket(); // Reset all one-time use values in the packet, so we can reuse it _currentUpdatePacket.ResetValues(); } // Before we add another item to our queue, we check whether some // already exceed the maximum expected RTT foreach (var seqStopwatchPair in _sentQueue.GetCopy()) { if (seqStopwatchPair.Value.ElapsedMilliseconds > MaximumExpectedRtt) { _sentQueue.Remove(seqStopwatchPair.Key); } } // Now we add our new sequence number into the queue with a running stopwatch var stopwatch = new Stopwatch(); stopwatch.Start(); _sentQueue[_sequenceNumber] = stopwatch; // Increase (and potentially loop) the current sequence number if (_sequenceNumber == ushort.MaxValue) { _sequenceNumber = 0; } else { _sequenceNumber++; } _udpNetClient.Send(packet); }