lsalzman / enet

ENet reliable UDP networking library
MIT License
2.71k stars 668 forks source link

Q: The best way to use #135

Open DmitruMoth opened 4 years ago

DmitruMoth commented 4 years ago

Hello, im trying to make simple multiplayer game. I have this model: client send to server what he wants to do, server do this, and send result back to the client. I use box2d on Server to emulate physic, and send to client his position using FlatBuffers. On client side i have code like this:

void update() //calling with 60 FPS
{
ENetEvent event;
if(enet_host_service(client, &event, 0) > 0)
{
//handle data
}
//do something with received data

sendData(); //function send what client wants to do

}

On server side:

void update()
{
ENetEvent event;
if(enet_host_service(server, &event, 16) > 0) // aka 60 fps
{
//handle data
}

//simulating world

for(const auto &player : players) 
{
//send player snapshot via enet_host_broadcast
}
}

All works fine, but only if i have 1 client, and time for waiting on server side > 40 ms If i have more than 1 client, i have very big ping So, i have next questionns;

  1. Which flag for sending packet should i use?
  2. How should i send and receive packet and how often?
  3. Common tips about multiplayer game Will be fine see any complete project with multiplayer(more fine if it using enet) or/and any books/article/etc Thanks!
bjorn commented 4 years ago

Did you read the tutorial? Please at least go through the tutorial and then also check out the rest of the documentation. The API docs are a little terse sometimes, but it's quite useful to understand the features of ENet.

A basic thing you seem to have missed is that enet_host_service should be called in a loop because each invocation only gives you a single event. If there are more than 60 events per second, your client and server will run into problems.

DmitruMoth commented 4 years ago

Thanks for answer. Yeah, i read tutorial and documentation, but there is no usage for regular sending and receiving data, with it i have troubles p.s. i use enet_host_service in a loop

bjorn commented 4 years ago

p.s. i use enet_host_service in a loop

Are you sure? In the code you shared you did not.

DmitruMoth commented 4 years ago

update() calling in a while loop

JayFoxRox commented 4 years ago

I haven't used enet in years, but the tutorial makes strong implications about how to use the API.

So I believe you are still lacking one loop.

Here is what you probably need:

void update_network() {
    // Keep checking for events as long as we have some.
    // This is the `while` loop you are missing! Your code uses `if`, which isn't enough.
    while (enet_host_service (client, & event, 0) > 0) {
        switch (event.type) {
        case ENET_EVENT_TYPE_CONNECT: [...]
        case ENET_EVENT_TYPE_RECEIVE: [...]
        case ENET_EVENT_TYPE_DISCONNECT: [...]
        }
    }
}

And then your mainloop:

// While the app is running, handle frames.
// This is probably the loop you already have.
while(true) {
    update_network();
    other_stuff();
    draw();
}

So you need 2 loops. One to serve all enet events that were received so far, and another one to keep your actual main-loop running.

I assume you only have 1 loop so far (the one for the main-loop). This can lead to congestion because enet_host_service will only handle a single event. So if you only call enet_host_service once per frame (= 1 call to update per main-loop iteration), then events can pile up.

Example 1:

Example 2:

So it's important to keep servicing until there are no more events left.

You also shouldn't set a timeout of 16ms for a bunch of reasons:

To me, the API design implies that a timeout should be used for idling the CPU on a broadcast-sever or in a threaded environment (where you can block). Otherwise you should call with a timeout of 0.

DmitruMoth commented 4 years ago

@JayFoxRox thanks, this is what am i searching for Question about enet_host_service, if it is in a while loop condition, does it mean a loop will never break if a peers always sending data?(as in my case, peers regular sending their states) So, anyway, i should try to do this

bjorn commented 4 years ago

Question about enet_host_service, if it is in a while loop condition, does it mean a loop will never break if a peers always sending data?(as in my case, peers regular sending their states)

If you're afraid that there will always be another event waiting and you may not get around to anything else than handling events, you can call enet_host_service once and then do a while loop on enet_host_check_events. That way you process all currently waiting events but not any new events, as far as I know (I could be wrong about it, maybe it just avoids processing new outgoing messages - since the docs are a little terse you may want to check the code).