// Decompression part------------------------------------------------------------------ /// <summary> /// Read the given number of bits /// </summary> /// <param name="numBits"></param> /// <param name="BIS"></param> /// <returns></returns> private long ReadGivenBits(int numBits, BitInputStream BIS) { int bitsRead = 0; long check = BIS.ReadBits(numBits, out bitsRead); if (numBits != bitsRead) { throw new IOException(); } return(check); }
public static float[] getCompressedFloatsArray(byte[] data, float precision) { if (data == null || data.Length == 0) { return(new float[0]); } BitInputStream bitInputStream = new BitInputStream(data); int min = bitInputStream.ReadBits(24) - MIDDLE_VALUE; int bitsSize = bitInputStream.ReadBits(8); int size = bitInputStream.ReadBits(24); float[] values = new float[size]; for (int i = 0; i < values.Length; i++) { int read = bitInputStream.ReadBits(bitsSize); values[i] = (min + read) * precision; } return(values); }
public void BitStream_AlignAndByteArray() { var random = new Random(1293); var numbers = new int[1024]; var payload = new byte[32]; var payloadCompare = new byte[32]; random.NextBytes(payload); var buffer = new byte[1024 * 1024]; for (int runs = 0; runs < 1; ++runs) { for (int i = 0; i < 1024; ++i) { numbers[i] = random.Next(1, 33); } var output = new BitOutputStream(buffer); for (int i = 0; i < 1024; ++i) { output.WriteBits((uint)numbers[i], numbers[i]); if (i % 3 == 0) { output.WriteBytes(payload, 0, numbers[i]); } } var input = new BitInputStream(buffer); for (int i = 0; i < 1024; ++i) { var value = input.ReadBits(numbers[i]); Assert.AreEqual((uint)numbers[i], value); if (i % 3 == 0) { input.ReadBytes(payloadCompare, 0, numbers[i]); Assert.AreEqual(0, NetworkUtils.MemCmp(payload, 0, payloadCompare, 0, numbers[i])); } } } }
public void BitStream_Align() { var random = new Random(1293); var numbers = new int[1024]; var buffer = new byte[1024 * 64]; for (int runs = 0; runs < 1000; ++runs) { for (int i = 0; i < 1024; ++i) { numbers[i] = random.Next(1, 33); } var output = new BitOutputStream(buffer); for (int i = 0; i < 1024; ++i) { output.WriteBits((uint)numbers[i], numbers[i]); if (i % 3 == 0) { output.Align(); } } var input = new BitInputStream(buffer); for (int i = 0; i < 1024; ++i) { var value = input.ReadBits(numbers[i]); Assert.AreEqual((uint)numbers[i], value); if (i % 3 == 0) { input.Align(); } } } }
// Decompression part------------------------------------------------------------------ /// <summary> /// Read the given number of bits /// </summary> /// <param name="numBits"></param> /// <param name="BIS"></param> /// <returns></returns> private long ReadGivenBits(int numBits, BitInputStream BIS) { int bitsRead = 0; long check = BIS.ReadBits(numBits, out bitsRead); if(numBits != bitsRead) { throw new IOException(); } return check; }
// Returns the 'wide' packageSequenceNumber (i.e. 32 bit reconstructed from the 16bits sent over wire) protected int ProcessPackageHeader(byte[] packageData, int packageSize, out NetworkMessage content, out byte[] assembledData, out int assembledSize, out int headerSize) { counters.packagesIn++; assembledData = packageData; assembledSize = packageSize; headerSize = 0; var input = new BitInputStream(packageData); int headerStartInBits = input.GetBitPosition(); content = (NetworkMessage)input.ReadBits(8); // TODO: Possible improvement is to ack on individual fragments not just entire message if ((content & NetworkMessage.FRAGMENT) != 0) { // Package fragment var fragmentPackageSequence = Sequence.FromUInt16((ushort)input.ReadBits(16), inSequence); var numFragments = (int)input.ReadBits(8); var fragmentIndex = (int)input.ReadBits(8); var fragmentSize = (int)input.ReadBits(16); FragmentReassemblyInfo assembly; if (!m_FragmentReassembly.TryGetValue(fragmentPackageSequence, out assembly)) { // If we run out of room in the reassembly buffer we will not be able to reassemble this package if (!m_FragmentReassembly.Available(fragmentPackageSequence)) { counters.fragmentedPackagesLostIn++; } GameDebug.Assert(numFragments <= NetworkConfig.maxFragments); assembly = m_FragmentReassembly.Acquire(fragmentPackageSequence); assembly.numFragments = numFragments; assembly.receivedMask = 0; assembly.receivedCount = 0; } GameDebug.Assert(assembly.numFragments == numFragments); GameDebug.Assert(fragmentIndex < assembly.numFragments); counters.headerBitsIn += input.GetBitPosition() - headerStartInBits; if ((assembly.receivedMask & (1U << fragmentIndex)) != 0) { // Duplicate package fragment counters.packagesDuplicateIn++; return(0); } assembly.receivedMask |= 1U << fragmentIndex; assembly.receivedCount++; input.ReadBytes(assembly.data, fragmentIndex * NetworkConfig.packageFragmentSize, fragmentSize); if (assembly.receivedCount < assembly.numFragments) { return(0); // Not fully assembled } // Continue processing package as we have now reassembled the package assembledData = assembly.data; assembledSize = fragmentIndex * NetworkConfig.packageFragmentSize + fragmentSize; input.Initialize(assembledData); headerStartInBits = 0; content = (NetworkMessage)input.ReadBits(8); } var inSequenceNew = Sequence.FromUInt16((ushort)input.ReadBits(16), inSequence); var outSequenceAckNew = Sequence.FromUInt16((ushort)input.ReadBits(16), outSequenceAck); var outSequenceAckMaskNew = (ushort)input.ReadBits(16); if (inSequenceNew > inSequence) { // If we have a hole in the package sequence that will fall off the ack mask that // means the package (inSequenceNew-15 and before) will be considered lost (either it will never come or we will // reject it as being stale if we get it at a later point in time) var distance = inSequenceNew - inSequence; for (var i = 0; i < Math.Min(distance, 15); ++i) // TODO : Fix this contant { if ((inSequenceAckMask & 1 << (15 - i)) == 0) { counters.packagesLostIn++; } } // If there is a really big hole then those packages are considered lost as well // Update the incoming ack mask. if (distance > 15) { counters.packagesLostIn += distance - 15; inSequenceAckMask = 1; // all is lost except current package } else { inSequenceAckMask <<= distance; inSequenceAckMask |= 1; } inSequence = inSequenceNew; inSequenceTime = NetworkUtils.stopwatch.ElapsedMilliseconds; } else if (inSequenceNew < inSequence) { // Package is out of order // Check if the package is stale // NOTE : We rely on the fact that we will reject packages that we cannot ack due to the size // of the ack mask, so we don't have to worry about resending messages as long as we do that // after the original package has fallen off the ack mask. var distance = inSequence - inSequenceNew; if (distance > 15) // TODO : Fix this constant { counters.packagesStaleIn++; return(0); } // Check if the package is a duplicate var ackBit = 1 << distance; if ((ackBit & inSequenceAckMask) != 0) { // Duplicate package counters.packagesDuplicateIn++; return(0); } // Accept the package out of order counters.packagesOutOfOrderIn++; inSequenceAckMask |= (ushort)ackBit; } else { // Duplicate package counters.packagesDuplicateIn++; return(0); } if (inSequenceNew % 3 == 0) { var timeOnServer = (ushort)input.ReadBits(8); TPackageInfo info; if (outstandingPackages.TryGetValue(outSequenceAckNew, out info)) { var now = NetworkUtils.stopwatch.ElapsedMilliseconds; rtt = (int)(now - info.sentTime - timeOnServer); } } // If the ack sequence is not higher we have nothing new to do if (outSequenceAckNew <= outSequenceAck) { headerSize = input.Align(); return(inSequenceNew); } // Find the sequence numbers that we have to consider lost var seqsBeforeThisAlreadyNotifedAsLost = outSequenceAck - 15; var seqsBeforeThisAreLost = outSequenceAckNew - 15; for (int sequence = seqsBeforeThisAlreadyNotifedAsLost; sequence <= seqsBeforeThisAreLost; ++sequence) { // Handle conditions before first 15 packets if (sequence < 0) { continue; } // If seqence covered by old ack mask, we may already have received it (and notified) int bitnum = outSequenceAck - sequence; var ackBit = bitnum >= 0 ? 1 << bitnum : 0; var notNotified = (ackBit & outSequenceAckMask) == 0; if (outstandingPackages.Exists(sequence) && notNotified) { var info = outstandingPackages[sequence]; NotifyDelivered(sequence, info, false); counters.packagesLostOut++; if (info.fragmented) { counters.fragmentedPackagesLostOut++; } info.Reset(); outstandingPackages.Remove(sequence); } } outSequenceAck = outSequenceAckNew; outSequenceAckMask = outSequenceAckMaskNew; // Ack packages if they haven't been acked already for (var sequence = Math.Max(outSequenceAck - 15, 0); sequence <= outSequenceAck; ++sequence) { var ackBit = 1 << outSequenceAck - sequence; if (outstandingPackages.Exists(sequence) && (ackBit & outSequenceAckMask) != 0) { var info = outstandingPackages[sequence]; NotifyDelivered(sequence, info, true); info.Reset(); outstandingPackages.Remove(sequence); } } counters.headerBitsIn += input.GetBitPosition() - headerStartInBits; headerSize = input.Align(); return(inSequenceNew); }
/// <summary> /// Retrieves a specific Huffman tree from the array of them. /// </summary> /// <param name="inputStream">Stream to read bits from</param> /// <param name="huffTrees">Array of Huffman trees to choose from</param> /// <param name="numberOfTrees">Number of filled trees in the array</param> /// <returns>Returns the Huffman tree that is needed that is requested in the BitStream.</returns> private BinaryTreeNode<byte> RetrieveHuffmanTree(BitInputStream inputStream, BinaryTreeNode<byte>[] huffTrees, int numberOfTrees) { int bitsRead = 0; int spot = (int)inputStream.ReadBits(9, out bitsRead); if (bitsRead < 9) throw new IOException(_errorMessage); return huffTrees[spot]; }
/// <summary> /// Reads Bits from given BitInputStream /// </summary> /// <param name="inputStream">Stream to read from</param> /// <param name="numberToRead">Number of bits to read from the stream.</param> /// <returns>A long of the bits in the stream.</returns> private long ReadBits(BitInputStream inputStream, int numberToRead) { int numRead = 0; long results = inputStream.ReadBits(numberToRead, out numRead); if (numRead == 0) throw new IOException(_errorMessage); else return results; }
public int ProcessPackageHeader(byte[] packageData, out NetworkMessage content, out int headerSize) { counters.packagesIn++; var input = new BitInputStream(packageData); headerSize = 0; int headerStartInBits = input.GetBitPosition(); content = (NetworkMessage)input.ReadBits(8); var inSequenceNew = Sequence.FromUInt16((ushort)input.ReadBits(16), inSequence); var outSequenceAckNew = Sequence.FromUInt16((ushort)input.ReadBits(16), outSequenceAck); var outSequenceAckMaskNew = (ushort)input.ReadBits(16); if (inSequenceNew > inSequence) { // If we have a hole in the package sequence that will fall off the ack mask that // means the package (inSequenceNew-15 and before) will be considered lost (either it will never come or we will // reject it as being stale if we get it at a later point in time) var distance = inSequenceNew - inSequence; for (var i = 0; i < Math.Min(distance, 15); ++i) // TODO : Fix this contant { if ((inSequenceAckMask & 1 << (15 - i)) == 0) { counters.packagesLostIn++; } } // If there is a really big hole then those packages are considered lost as well // Update the incoming ack mask. if (distance > 15) { counters.packagesLostIn += distance - 15; inSequenceAckMask = 1; // all is lost except current package } else { inSequenceAckMask <<= distance; inSequenceAckMask |= 1; } inSequence = inSequenceNew; inSequenceTime = NetworkUtils.stopwatch.ElapsedMilliseconds; } else if (inSequenceNew < inSequence) { // Package is out of order // Check if the package is stale var distance = inSequence - inSequenceNew; if (distance > 15) // TODO : Fix this constant { counters.packagesStaleIn++; return(0); } // Check if the package is a duplicate var ackBit = 1 << distance; if ((ackBit & inSequenceAckMask) != 0) { // Duplicate package counters.packagesDuplicateIn++; return(0); } // Accept the package out of order //counters.packagesOutOfOrderIn++; inSequenceAckMask |= (ushort)ackBit; } else { // Duplicate package counters.packagesDuplicateIn++; return(0); } if (inSequenceNew % 3 == 0) { var timeOnServer = (ushort)input.ReadBits(8); TPackageInfo info; if (outstandingPackages.TryGetValue(outSequenceAckNew, out info)) { var now = NetworkUtils.stopwatch.ElapsedMilliseconds; rtt = (int)(now - info.SentTime - timeOnServer); } } // If the ack sequence is not higher we have nothing new to do if (outSequenceAckNew <= outSequenceAck) { headerSize = input.Align(); return(inSequenceNew); } // Find the sequence numbers that we have to consider lost var seqsBeforeThisAlreadyNotifedAsLost = outSequenceAck - 15; var seqsBeforeThisAreLost = outSequenceAckNew - 15; for (int sequence = seqsBeforeThisAlreadyNotifedAsLost; sequence <= seqsBeforeThisAreLost; ++sequence) { // Handle conditions before first 15 packets if (sequence < 0) { continue; } // If seqence covered by old ack mask, we may already have received it (and notified) int bitnum = outSequenceAck - sequence; var ackBit = bitnum >= 0 ? 1 << bitnum : 0; var notNotified = (ackBit & outSequenceAckMask) == 0; if (outstandingPackages.Exists(sequence) && notNotified) { var info = outstandingPackages[sequence]; NotifyDelivered(sequence, info, false); counters.packagesLostOut++; info.Reset(); outstandingPackages.Remove(sequence); } } outSequenceAck = outSequenceAckNew; outSequenceAckMask = outSequenceAckMaskNew; // Ack packages if they haven't been acked already for (var sequence = Math.Max(outSequenceAck - 15, 0); sequence <= outSequenceAck; ++sequence) { var ackBit = 1 << outSequenceAck - sequence; if (outstandingPackages.Exists(sequence) && (ackBit & outSequenceAckMask) != 0) { var info = outstandingPackages[sequence]; NotifyDelivered(sequence, info, true); info.Reset(); outstandingPackages.Remove(sequence); } } headerSize = input.Align(); return(inSequenceNew); }