Пример #1
0
    public void CopyByteArray(ref BitInputStream input)
    {
        var count = (int)input.ReadUIntPacked();

        WriteUIntPacked((uint)count);
        if (count > 0)
        {
            Align();
            input.Align();
            input.ReadBytes(m_Buffer, m_CurrentByteIdx, count);
            m_CurrentByteIdx += count;
        }
    }
Пример #2
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();
                    }
                }
            }
        }
Пример #3
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);
    }
Пример #4
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);
    }