//ProcessAck in packet
        public void ProcessAck(NetPacket packet)
        {
            ushort ackWindowStart = packet.Sequence;

            if (ackWindowStart >= NetConstants.MaxSequence)
            {
                NetUtils.DebugWrite("[PA]Bad window start");
                return;
            }

            byte[] acksData = packet.RawData;
            NetUtils.DebugWrite("[PA]AcksStart: {0}", ackWindowStart);
            //Monitor.Enter(_pendingPackets);

            for (int i = 0; i < packet.GetDataSize(); ++i)
            {
                byte acksByte = acksData[i];
                for (int idx = 0; idx < 8; ++idx)
                {
                    if ((acksByte & (1 << idx)) == 0)
                    {
                        // Packet not ack, will be resent automaticaly as needed
                        continue;
                    }

                    // packet acknowledged = true
                    int seqAck = NetUtils.IncrementSequenceNumber(ackWindowStart, i * 8 + idx);

                    PendingPacket pendingPacket = _tailPendingPacket;
                    PendingPacket prevPacket    = null;
                    while (pendingPacket != _headPendingPacket)
                    {
                        // Looking for the packet to acknowledge
                        if (pendingPacket.Packet == null || pendingPacket.Packet.Sequence != seqAck)
                        {
                            prevPacket    = pendingPacket;
                            pendingPacket = pendingPacket.Next;
                            continue;
                        }

                        //clear acked packet
                        pendingPacket.Packet.DontRecycleNow = false;
                        pendingPacket.Packet.Recycle();
                        pendingPacket.Clear();

                        // Packet found, remove it from the list
                        while (_tailPendingPacket.Packet == null && _tailPendingPacket != _headPendingPacket)
                        {
                            _tailPendingPacket = _tailPendingPacket.Next;
                        }

                        NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - true", seqAck);
                        break;
                    }
                }
            }
            packet.Recycle();
            //Monitor.Exit(_pendingPackets);
        }
        //ProcessAck in packet
        public void ProcessAck(NetPacket packet)
        {
            int validPacketSize = (_windowSize - 1) / BitsInByte + 1 + NetConstants.SequencedHeaderSize;

            if (packet.Size != validPacketSize)
            {
                NetUtils.DebugWrite("[PA]Invalid acks packet size");
                return;
            }

            ushort ackWindowStart = packet.Sequence;

            if (ackWindowStart > NetConstants.MaxSequence)
            {
                NetUtils.DebugWrite("[PA]Bad window start");
                return;
            }

            //check relevance
            if (NetUtils.RelativeSequenceNumber(ackWindowStart, _localWindowStart) <= -_windowSize)
            {
                NetUtils.DebugWrite("[PA]Old acks");
                return;
            }

            byte[] acksData = packet.RawData;
            NetUtils.DebugWrite("[PA]AcksStart: {0}", ackWindowStart);
            int startByte = NetConstants.SequencedHeaderSize;

            Monitor.Enter(_pendingPackets);
            for (int i = 0; i < _windowSize; i++)
            {
                int ackSequence = (ackWindowStart + i) % NetConstants.MaxSequence;
                if (NetUtils.RelativeSequenceNumber(ackSequence, _localWindowStart) < 0)
                {
                    //NetUtils.DebugWrite(ConsoleColor.Cyan, "[PA] SKIP OLD: " + ackSequence);
                    //Skip old ack
                    continue;
                }

                int currentByte = startByte + i / BitsInByte;
                int currentBit  = i % BitsInByte;

                if ((acksData[currentByte] & (1 << currentBit)) == 0)
                {
#if STATS_ENABLED || DEBUG
                    if (_pendingPackets[ackSequence % _windowSize].TimeStamp.HasValue)
                    {
                        _peer.Statistics.PacketLoss++;
                    }
#endif
                    //NetUtils.DebugWrite(ConsoleColor.Cyan, "[PA] SKIP FALSE: " + ackSequence);
                    //Skip false ack
                    continue;
                }

                if (ackSequence == _localWindowStart)
                {
                    //Move window
                    _localWindowStart = (_localWindowStart + 1) % NetConstants.MaxSequence;
                }

                PendingPacket pendingPacket = _pendingPackets[ackSequence % _windowSize];
                if (pendingPacket.Packet != null)
                {
                    if (pendingPacket == _headPendingPacket)
                    {
                        _headPendingPacket = _headPendingPacket.Prev;
                    }
                    _peer.Recycle(pendingPacket.Packet);
                    pendingPacket.Clear();
                    NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - true", ackSequence);
                }
                else
                {
                    NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - false", ackSequence);
                }
            }
            Monitor.Exit(_pendingPackets);
        }