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); }
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); }
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); } } }