Пример #1
0
        // 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);
        }
Пример #3
0
        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]));
                    }
                }
            }
        }
Пример #4
0
        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();
                    }
                }
            }
        }
Пример #5
0
 // 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;
 }
Пример #6
0
    // 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);
    }
Пример #7
0
        /// <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];
        }
Пример #8
0
        /// <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;
        }
Пример #9
0
    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);
    }