lsalzman / enet

ENet reliable UDP networking library
MIT License
2.73k stars 670 forks source link

Lag over time? #203

Closed lolriven closed 2 years ago

lolriven commented 2 years ago

I'm having a strange issue with ENet which I can't narrow down. I'm sending packets between two peers every frame, initially the packets arrive on time within 1 frame of each-other since both clients are running on the same machine for testing. But after about a minute passes, the packets start becoming more and more delayed. To where packets arrive 30 frames late. I'm not doing anything in my game loop which would cause delay in sending or receiving the packets since both clients are running consistent 70 fps. Is this a known issue with ENet? Has anyone else experienced it? To give a small demonstration of what's happening, here's two rectangles moving around. The one on the left is being controlled while the one on the right is seeing the result across the network. The one on the right is receiving the packets much later than when they were actually sent.. Even though they're both running on the same machine. The packets I am sending (PacketTransmission) is only 16 bytes.

https://imgur.com/bumbAvg https://i.imgur.com/bumbAvg.mp4

This is how I'm sending the packets.

    ENetPacket *packet = enet_packet_create((uint8_t*)pt,
                                            sizeof(PacketTransmission),
                                            ENET_PACKET_FLAG_RELIABLE);

    enet_peer_send(c->natpeer, 0, packet);
lsalzman commented 2 years ago

It's likely you're not calling enet_host_service/enet_host_check_events enough to consume all sent packets each frame.

lolriven commented 2 years ago

@lsalzman Thank you for the reply. I am calling enet_host_service every frame, to poll for network data. But I'm not calling enet_host_check_events. How much difference would that make? I assumed only enet_host_service is necessary since it will relay any que'd packets as well as read anything available. But yes every frame iteration I am calling enet_host_service; however, when I do call it I use a timeout of 0, would increasing that timeout help?

lsalzman commented 2 years ago

You have to call enet_host_service multiple times until it returns no events, every frame. Not just once per frame...

lolriven commented 2 years ago

You have to call enet_host_service multiple times until it returns no events, every frame. Not just once per frame...

Oh! I actually wasn't aware of that! Thank you! I'll check the results and let you know after!

lsalzman commented 2 years ago

An alternative is to call enet_host_service once per frame, but call enet_host_check_events thereafter multiple times until there are no more events left. That strategy can be used if calling enet_host_service many times per frames somehow becomes a performance issue.

lolriven commented 2 years ago

I changed the code to where it will call enet_host_service once, then call enet_host_check_events in a loop until there are no more events. It doesn't seem to solve the issue because the initial frame latency is 4 frames, over time it becomes 5, then 6 and more later on. Here's my code.

    ENetEvent event;

    auto packethandler = [this,callback,c](const ENetEvent& event){

        if (event.type == ENET_EVENT_TYPE_RECEIVE){

            PacketTransmission* received = (PacketTransmission*)event.packet->data;

            if(event.packet->dataLength==sizeof(PacketTransmission)){

                if(PACK_GET_SIG(received)==GAMESIGNATURE||PACK_GET_SIG(received)==NATSIGNATURE){
                    //incase packets aren't encrypted just do callback
                    callback(received, event.packet->dataLength);
                }else{
                    //incase packets are encrypted, decrypt, callback
                    decryptpacket(received);

                    callback(received, event.packet->dataLength);
                }

            }
            enet_packet_destroy(event.packet);
        }
        else if (event.type == ENET_EVENT_TYPE_NONE){
            //nothing
        }

    };
    //call enet_host_service once ,
    int result = enet_host_service(c->client, &event, timeout);

    if(result>0){

        //events available,
        packethandler(event);

        //call enet_host_check_events in a  loop
        while(enet_host_check_events(c->client,&event)){
            packethandler(event);
        }
    }
bjorn commented 2 years ago

@JadeVand I don't see how there could still be lag from your code snippet, but I just thought I'd mention that if you're using enet_host_check_events, then you can just call enet_host_service with a nullptr for the event (and ignore the return value), which will simplify your code.

lolriven commented 2 years ago

@bjorn Thank you, I'll do that. It would make the code simpler and cleaner. But I can't find the source of the lag either.