// on user thread // the message must not be sent already private NetSendResult SendFragmentedMessage( NetOutgoingMessage message, IEnumerable <NetConnection?> recipients, NetDeliveryMethod method, int sequenceChannel) { // determine minimum mtu for all recipients int mtu = GetMTU(recipients, out int recipientCount); if (recipientCount == 0) { Recycle(message); return(NetSendResult.NoRecipients); } int group = GetNextFragmentGroup(); // do not send msg; but set fragmentgroup in case user tries to recycle it immediately message._fragmentGroup = group << 2 | 1; // create fragmentation specifics int totalBytes = message.ByteLength; int bytesPerChunk = NetFragmentationHelper.GetBestChunkSize(group, totalBytes, mtu); int numChunks = totalBytes / bytesPerChunk; if (numChunks * bytesPerChunk < totalBytes) { numChunks++; } var retval = NetSendResult.Sent; int bitsPerChunk = bytesPerChunk * 8; int bitsLeft = message.BitLength; byte[] buffer = message.GetBuffer(); for (int i = 0; i < numChunks; i++) { NetOutgoingMessage chunk = CreateMessage(); chunk.SetBuffer(buffer, false); chunk.BitLength = Math.Min(bitsLeft, bitsPerChunk); chunk._fragmentGroup = group << 2 | 1; chunk._fragmentGroupTotalBits = totalBytes * 8; chunk._fragmentChunkByteSize = bytesPerChunk; chunk._fragmentChunkNumber = i; LidgrenException.Assert(chunk.BitLength != 0); LidgrenException.Assert(chunk.GetEncodedSize() <= mtu); Interlocked.Add(ref chunk._recyclingCount, recipientCount); foreach (NetConnection?recipient in recipients.AsListEnumerator()) { if (recipient == null) { continue; } NetSendResult result = recipient.EnqueueMessage(chunk, method, sequenceChannel).Result; if (result > retval) { retval = result; // return "worst" result } } bitsLeft -= bitsPerChunk; } return(retval); }