예제 #1
0
 public void Add(SuperPacketReader reader)
 {
     lock (_lock)
     {
         _internalList.Add(reader.id(), reader);
     }
 }
예제 #2
0
        public void onReceivedSafe(ushort tickId, byte[] data, int size)
        {
            SuperPacketReader reader = new SuperPacketReader(data, size);

            protocol.HandleServerTick(reader, superPacket);
            protocol.getPhaseSync().EarlyOneShot(() => onReceivedImpl(tickId, reader));
        }
예제 #3
0
        public void onReceivedUnsafe(ushort tickId, byte[] data, int size)
        {
            SuperPacketReader reader = new SuperPacketReader(data, size);

            protocol.HandleServerTick(reader, superPacket);
            onReceivedImpl(tickId, reader);
        }
예제 #4
0
        private void read_impl(IBaseClient client, SuperPacket <PQ> superpacket, IMarshal marshal)
        {
            SuperPacketReader reader = client.popPendingSuperPacket();

            // Handshake process skips all procedures, including order
            if (reader.HasFlag(SuperPacketFlags.Handshake))
            {
                // Nothing to do here, it's a handshake packet
                // TODO(gpascualg): We don't need to add them at all
                LastTickIdRead = reader.tickId();
                return;
            }

            Debug.Assert(!IsOutOfOrder(reader.tickId()), "Should never have out of order packets");

            if (Overflow.sub(ExpectedTickId, reader.tickId()) > Constants.MaximumBlocksUntilResync)
            {
                superpacket.SetFlag(SuperPacketFlags.Handshake);
            }

            if (LastTickIdRead > reader.tickId())
            {
                loopCounter = (byte)(loopCounter + 1);
            }

            LastTickIdRead = reader.tickId();
            reader.handlePackets <PQ, IBaseClient>(this, marshal, client);
        }
예제 #5
0
        public void HandleServerTick(SuperPacketReader reader, SuperPacket <PQ> superpacket)
        {
            // Update sizes
            recvKbpsEstimateAcc += reader.size();
            lastRecvSize        += reader.size();
            perTickSize.AddOrUpdate(reader.tickId(), reader.size(), (key, old) => old + reader.size());

            // Check handshake status
            if (!superpacket.HasFlag(SuperPacketFlags.Handshake))
            {
                LastServerId = Overflow.max(LastServerId, reader.tickId());

                // TODO(gpascualg): Make phase sync id diff optional
                int idDiff = Overflow.signed_diff(phaseSync.TickId, LastServerId);
                ServerTimeDiff = idDiff - (estimatedRTT / 50.0f + 1); //- (int)(estimatedRTT / 2.0f);
            }
            else
            {
                // Fix phase sync, otherwise we will get a huge spike
                LastServerId = reader.tickId();
                if (serverBasedSync)
                {
                    phaseSync.FixTickId(LastServerId);
                }
            }

            // Update PLL
            phaseSync.ServerPacket(reader.tickId(), LastServerId);
        }
예제 #6
0
        public bool PeekFirst(out SuperPacketReader reader)
        {
            reader = null;
            lock (_lock)
            {
                if (_internalList.Count > 0)
                {
                    reader = _internalList.Values[0];
                    return(true);
                }
            }

            return(false);
        }
예제 #7
0
        public SuperPacketReader PopFirstOrNull()
        {
            lock (_lock)
            {
                if (_internalList.Count > 0)
                {
                    SuperPacketReader reader = _internalList.Values[0];
                    _internalList.RemoveAt(0);
                    return(reader);
                }
            }

            return(null);
        }
예제 #8
0
        private void onReceivedImpl(ushort tickId, SuperPacketReader reader)
        {
            if (DropRecv())
            {
                return;
            }

            if (protocol.IsOutOfOrder(reader.tickId()) && !reader.HasFlag(SuperPacketFlags.Handshake))
            {
                return;
            }

            // Add to pending list
            pendingPackets.Add(reader);
            lastPacketID   = reader.id();
            lastPacketSize = reader.size();

            // Handle all acks already
            protocol.HandleAcks(tickId, reader, superPacket, marshal);
        }
예제 #9
0
        public void HandleAcks(ushort tickId, SuperPacketReader reader, SuperPacket <PQ> superpacket, IMarshal marshal)
        {
            // Ack packets
            foreach (ushort ack in reader.getAcks())
            {
                // Check if this ack > lastAck
                if (Kaminari.Overflow.ge(ack, processedAckBase))
                {
                    int displace = Kaminari.Overflow.sub(ack, processedAckBase);
                    processedAcks    = processedAcks << displace;
                    processedAckBase = ack;
                }

                // Now, check if the ack has already been processed
                int ackPosition = Overflow.sub(processedAckBase, ack);
                if (ackPosition >= 64)
                {
                    ackPosition      = 0;
                    processedAcks    = 0;
                    processedAckBase = ack;
                }

                // If it is already masked, it means it has already been processed
                ulong ackMask = (ulong)1 << ackPosition;
                if ((processedAcks & ackMask) > 0)
                {
                    continue;
                }
                processedAcks = processedAcks | ackMask;

                // Otherwise, let superpacker handle the ack
                superpacket.Ack(ack);

                // Update lag estimation
                if (Overflow.geq(lastConfirmedTimestampId, ack) && Overflow.sub(timestampsHeadId, lastConfirmedTimestampId) < 100)
                {
                    // TODO(gpascualg): This can be used as a connection quality estimate
                    continue;
                }

                lastConfirmedTimestampId = ack;
                ushort position = Overflow.mod(Overflow.sub(timestampsHeadPosition, Overflow.sub(timestampsHeadId, ack)), ResolutionTableSize);
                ulong  diff     = reader.Timestamp - timestamps[position];
                UnityEngine.Debug.Log($"> ACK {ack} AT {position} +{diff}");
                const float w = 0.99f;
                estimatedRTT = estimatedRTT * w + diff * (1.0f - w);
            }

            // Schedule ack if necessary
            bool is_handshake = reader.HasFlag(SuperPacketFlags.Handshake);

            if (is_handshake || reader.hasData() || reader.isPingPacket())
            {
                superpacket.scheduleAck(reader.id());
            }

            // Handle flags already
            if (is_handshake)
            {
                // Check if there was too much of a difference, in which case, flag handshake again
                // TODO(gpascualg): Remove re-handshake max diff magic number
                if (Overflow.abs_diff(reader.tickId(), tickId) > 10)
                {
                    superpacket.SetFlag(SuperPacketFlags.Handshake);
                }

                // During handshake, we update our tick to match the other side
                ExpectedTickId = reader.tickId();
                LastServerId   = reader.tickId();

                // Reset all variables related to packet parsing
                timestampBlockId = ExpectedTickId;
                timestamp        = DateTimeExtensions.now();
                loopCounter      = 0;

                // Reset marshal
                ResetResolutionTable(reader.tickId());
                marshal.Reset();

                if (!reader.HasFlag(SuperPacketFlags.Ack))
                {
                    superpacket.SetFlag(SuperPacketFlags.Ack);
                    superpacket.SetFlag(SuperPacketFlags.Handshake);
                }
            }
        }