public void Reset()
 {
     reliablePacketHeader = default;
     userPacketHeader     = default;
     stream            = default;
     receptionCallback = default;
 }
    public void OnReceiveData(byte[] data, IPEndPoint iPEndPoint)
    {
        MemoryStream  memoryStream  = new MemoryStream(data);
        PacketWithCrc packetWithCrc = new PacketWithCrc();

        packetWithCrc.Deserialize(memoryStream);
        memoryStream.Close();

        if (crc32.IsDataCorrupted(packetWithCrc.data, packetWithCrc.crc))
        {
            UnityEngine.Debug.LogError("Received corrupted data from " + iPEndPoint);
            return;
        }
        memoryStream = new MemoryStream(packetWithCrc.data);
        PacketHeader packetHeader = new PacketHeader();

        packetHeader.Deserialize(memoryStream);

        if ((PacketType)packetHeader.packetTypeID == PacketType.User)
        {
            UserPacketHeader userPacketHeader = new UserPacketHeader();
            userPacketHeader.Deserialize(memoryStream);

            ReliablePacketHeader reliablePacketHeader = new ReliablePacketHeader();
            reliablePacketHeader.Deserialize(memoryStream);
            ProcessReliablePacketReceived(reliablePacketHeader);

            InvokeCallback(userPacketHeader, memoryStream);
        }
        else
        {
            NetworkManager.Instance.OnReceivePacket(iPEndPoint, (PacketType)packetHeader.packetTypeID, memoryStream);
        }
        memoryStream.Close();
    }
    void ProcessReceivedAcknowledgeInfo(ReliablePacketHeader reliablePacketHeader, uint senderID)
    {
        int ackBits      = reliablePacketHeader.AckBits;
        int pendingIndex = -1;
        int i            = 1;

        do
        {
            if ((ackBits & 1) != 0)
            {
                pendingIndex = Array.FindIndex(packetsPendingAck[senderID], ppa => ppa.packetID == reliablePacketHeader.Acknowledge);

                if (pendingIndex != -1)
                {
                    packetsPendingAck[senderID][pendingIndex].Reset();
                }
            }
            ackBits >>= 1;
            i++;
        } while (ackBits != 0);

        pendingIndex = -1;
        pendingIndex = Array.FindIndex(packetsPendingAck[senderID], ppa => ppa.packetID == reliablePacketHeader.Acknowledge);

        if (pendingIndex != -1)
        {
            packetsPendingAck[senderID][pendingIndex].Reset();
        }
    }
    public byte[] SerializePacket <T>(NetworkPacket <T> networkPacket, uint senderID = 0, uint objectID = 0,
                                      ReliablePacketHeader reliablePacketHeader      = null)
    {
        byte[] data = null;

        PacketWrapper packetWrapper = new PacketWrapper();
        MemoryStream  memoryStream  = new MemoryStream();
        PacketHeader  packetHeader  = new PacketHeader();

        packetHeader.ProtocolID      = ProtocolID;
        packetHeader.PacketTypeIndex = networkPacket.PacketTypeIndex;

        packetHeader.Serialize(memoryStream);

        if ((PacketType)networkPacket.PacketTypeIndex == PacketType.User)
        {
            UserNetworkPacket <T> userNetworkPacket = networkPacket as UserNetworkPacket <T>;
            UserPacketHeader      userPacketHeader  = new UserPacketHeader();

            userPacketHeader.UserPacketTypeIndex = userNetworkPacket.UserPacketTypeIndex;
            userPacketHeader.SenderID            = senderID;
            userPacketHeader.ObjectID            = objectID;
            userPacketHeader.Reliable            = (reliablePacketHeader != null);

            userPacketHeader.Serialize(memoryStream);

            if (reliablePacketHeader != null)
            {
                reliablePacketHeader.Serialize(memoryStream);
            }
        }

        networkPacket.Serialize(memoryStream);
        memoryStream.Close();

        data = memoryStream.ToArray();

        packetWrapper.Crc        = crcCalculator.ComputeCrc32(data);
        packetWrapper.PacketData = data;

        memoryStream = new MemoryStream();

        packetWrapper.Serialize(memoryStream);
        memoryStream.Close();

        data = memoryStream.ToArray();

        return(data);
    }
    private void ProcessReliablePacketReceived(ReliablePacketHeader reliablePacketHeader)
    {
        if (enablePacketLossSimulation && UnityEngine.Random.Range(0, 100) < porcentageOfPacketLossSimulation)
        {
            UnityEngine.Debug.Log("Packet lost simulation");
            return;
        }

        if (reliablePacketHeader.sequence > remoteSequence)
        {
            remoteSequence = reliablePacketHeader.sequence;
        }

        if (!sequenceNumbersReceived.Contains(reliablePacketHeader.sequence))
        {
            sequenceNumbersReceived.Enqueue(reliablePacketHeader.sequence);
        }

        if (sequenceNumbersReceived.Count > numberOfBitsInAck)
        {
            sequenceNumbersReceived.Dequeue();
        }

        int ackBits = reliablePacketHeader.ackBitfield;

        //UnityEngine.Debug.Log("Ackbits received: " + Convert.ToString(ackBits, 2));
        for (int i = 0; i < numberOfBitsInAck; i++)
        {
            if ((ackBits & (1 << i)) != 0)
            {
                int packetSequenceToAck = (int)(reliablePacketHeader.ack - i);

                //UnityEngine.Debug.Log("Bit at position " + i + " is set.");
                //UnityEngine.Debug.Log("Acknowledging packet sequence " + packetSequenceToAck);

                if (packetsPendingToBeAcked.ContainsKey((uint)packetSequenceToAck))
                {
                    //UnityEngine.Debug.Log("Removin packet Nro." + packetSequenceToAck + " from pending list");
                    packetsPendingToBeAcked.Remove((uint)packetSequenceToAck);
                }
            }
        }
    }
    public void ReceiveData(byte[] data, IPEndPoint ipEndPoint)
    {
        MemoryStream         memoryStream         = null;
        PacketHeader         packetHeader         = null;
        UserPacketHeader     userPacketHeader     = null;
        ReliablePacketHeader reliablePacketHeader = null;

        if (DeserializePacket(data, out memoryStream, out packetHeader, ref userPacketHeader, ref reliablePacketHeader))
        {
            if (packetHeader.ProtocolID == ProtocolID)
            {
                if (userPacketHeader != null)
                {
                    if (userPacketHeader.Reliable)
                    {
                        Action <ushort, uint, Stream> processCallback = GetPacketReceptionCallback(userPacketHeader.ObjectID);
                        PacketReliabilityManager.Instance.ProcessReceivedStream(memoryStream,
                                                                                userPacketHeader,
                                                                                reliablePacketHeader,
                                                                                processCallback);
                    }
                    else
                    {
                        InvokeReceptionCallback(userPacketHeader.ObjectID, userPacketHeader.UserPacketTypeIndex,
                                                userPacketHeader.SenderID, memoryStream);
                    }
                }
                else
                {
                    systemPacketReceptionCallback?.Invoke(packetHeader.PacketTypeIndex, ipEndPoint, memoryStream);
                }

                if (userPacketHeader == null || !userPacketHeader.Reliable)
                {
                    memoryStream.Close();
                }
            }
        }
    }
    bool DeserializePacket(byte[] data, out MemoryStream memoryStream, out PacketHeader packetHeader,
                           ref UserPacketHeader userPacketHeader, ref ReliablePacketHeader reliablePacketHeader)
    {
        bool isFaultless;

        PacketWrapper packetWrapper = new PacketWrapper();

        memoryStream = new MemoryStream(data);
        packetHeader = new PacketHeader();

        packetWrapper.Deserialize(memoryStream);

        memoryStream.Close();

        isFaultless = crcCalculator.PerformCrcCheck(packetWrapper.PacketData, packetWrapper.Crc);

        if (isFaultless)
        {
            memoryStream = new MemoryStream(packetWrapper.PacketData);

            packetHeader.Deserialize(memoryStream);

            if ((PacketType)packetHeader.PacketTypeIndex == PacketType.User)
            {
                userPacketHeader = new UserPacketHeader();
                userPacketHeader.Deserialize(memoryStream);

                if (userPacketHeader.Reliable)
                {
                    reliablePacketHeader = new ReliablePacketHeader();
                    reliablePacketHeader.Deserialize(memoryStream);
                }
            }
        }

        return(isFaultless);
    }
    public void SendPacket <T>(NetworkPacket <T> networkPacket, uint senderID, uint objectID)
    {
        foreach (uint recipientID in packetsPendingAck.Keys)
        {
            ReliablePacketHeader reliablePacketHeader = new ReliablePacketHeader();
            MemoryStream         memoryStream         = new MemoryStream();
            PacketPendingAck     packetPendingAck;
            byte[] dataToSend;
            int    packetID = currentPacketIDs[recipientID]++;

            reliablePacketHeader.PacketID    = packetID;
            reliablePacketHeader.Acknowledge = acknowledges[recipientID];
            reliablePacketHeader.AckBits     = ackBits[recipientID];

            dataToSend = PacketsManager.Instance.SerializePacket(networkPacket, senderID, objectID, reliablePacketHeader);

            packetPendingAck.recipientID = recipientID;
            packetPendingAck.packetID    = packetID;
            packetPendingAck.packetData  = dataToSend;

            packetsPendingAck[recipientID][packetID % AckBitsCount] = packetPendingAck;
            SendDataToDestination(dataToSend, recipientID);
        }
    }
    public void ProcessReceivedStream(Stream stream, UserPacketHeader userPacketHeader, ReliablePacketHeader reliablePacketHeader,
                                      Action <ushort, uint, Stream> processCallback)
    {
        uint senderID = (UdpNetworkManager.Instance.IsServer) ? userPacketHeader.SenderID : 0;

        if (reliablePacketHeader.PacketID >= nextExpectedIDs[senderID])
        {
            if (reliablePacketHeader.PacketID > acknowledges[senderID])
            {
                acknowledges[senderID] = reliablePacketHeader.PacketID;
            }
            receivedPacketIDs[senderID][reliablePacketHeader.PacketID % AckBitsCount] = reliablePacketHeader.PacketID;
            UpdateAcknowledgeBits(senderID);

            int packetIndex = reliablePacketHeader.PacketID % AckBitsCount;

            packetsPendingProcess[senderID][packetIndex].reliablePacketHeader = reliablePacketHeader;
            packetsPendingProcess[senderID][packetIndex].userPacketHeader     = userPacketHeader;
            packetsPendingProcess[senderID][packetIndex].stream            = stream;
            packetsPendingProcess[senderID][packetIndex].receptionCallback = processCallback;

            if (reliablePacketHeader.PacketID == nextExpectedIDs[senderID])
            {
                while (packetsPendingProcess[senderID][packetIndex].stream != null)
                {
                    processCallback(packetsPendingProcess[senderID][packetIndex].userPacketHeader.UserPacketTypeIndex,
                                    packetsPendingProcess[senderID][packetIndex].userPacketHeader.SenderID,
                                    packetsPendingProcess[senderID][packetIndex].stream);
                    packetsPendingProcess[senderID][packetIndex].stream.Close();
                    packetsPendingProcess[senderID][packetIndex].Reset();
                    packetIndex = (packetIndex + 1) % AckBitsCount;
                    nextExpectedIDs[senderID]++;
                }
            }

            ProcessReceivedAcknowledgeInfo(reliablePacketHeader, senderID);
        }
    }
    public byte[] SerializePacket <T>(NetworkPacket <T> packetToSerialize, bool isReliable = false, uint objectID = 0)
    {
        MemoryStream memoryStream = new MemoryStream();
        PacketHeader packetHeader = new PacketHeader();

        packetHeader.packetTypeID = (uint)packetToSerialize.type;
        packetHeader.Serialize(memoryStream);

        if (packetToSerialize.type == PacketType.User)
        {
            UserPacketHeader userPacketHeader = new UserPacketHeader();

            userPacketHeader.packetTypeID = packetToSerialize.userPacketTypeID;
            userPacketHeader.packetID     = localSequence;
            userPacketHeader.senderID     = NetworkManager.Instance.clientID;
            userPacketHeader.objectID     = objectID;
            userPacketHeader.isReliable   = isReliable;

            userPacketHeader.Serialize(memoryStream);


            ReliablePacketHeader reliablePacketHeader = new ReliablePacketHeader();

            reliablePacketHeader.sequence = localSequence;
            reliablePacketHeader.ack      = remoteSequence;

            //UnityEngine.Debug.Log("Setting up ackbits for packet Nro." + localSequence);
            ackBitfields = 0;
            for (int i = 0; i <= numberOfBitsInAck; i++)
            {
                if (sequenceNumbersReceived.Contains((uint)(remoteSequence - i)))
                {
                    //UnityEngine.Debug.Log("Sequence number is contained: " + (int)(expectedSequence - i));
                    ackBitfields |= 1 << i;
                }
            }
            //UnityEngine.Debug.Log("Ackbits to send: " + Convert.ToString(ackBitfields, 2));
            reliablePacketHeader.ackBitfield = ackBitfields;

            reliablePacketHeader.Serialize(memoryStream);
        }
        packetToSerialize.Serialize(memoryStream);

        PacketWithCrc packetWithCrc = new PacketWithCrc();

        packetWithCrc.crc        = crc32.CalculateCrc(memoryStream.ToArray());
        packetWithCrc.byteLength = memoryStream.ToArray().Length;
        packetWithCrc.data       = memoryStream.ToArray();
        memoryStream.Close();

        memoryStream = new MemoryStream();
        packetWithCrc.Serialize(memoryStream);
        memoryStream.Close();

        if (isReliable)
        {
            if (!packetsPendingToBeAcked.ContainsKey(localSequence))
            {
                packetsPendingToBeAcked.Add(localSequence, memoryStream.ToArray());
            }
        }

        return(memoryStream.ToArray());
    }