udp for sending state changes

Started by
12 comments, last by NightCabbage 14 years, 4 months ago
hi, I was just wondering... would udp be stable enough to send object state changes across a fps online game. for e.g. when one player opens a door an OPEN_DOOR msg could be sent in a udp packet to every other client but I've read that udp is unreliable and that packets could be lost so what if one client doesn't recieve the OPEN_DOOR msg and gets stuck outside (or inside) ?? and has to witness other players walking through a closed door? would I need to broadcast every object's state constantly every so often if I'm using udp? what about games like quake? they must need to send some pakcets of data at the beginning of the game to let players know about each other (names, character skins etc.) what if these get lost?
Advertisement
Look at question 12 of the Forum FAQ for how quake and others do things. About using UDP you can send reliable UDP packets by implementing parts of TCP yourself. Question 11 covers libraries. ENet and others have support for reliable UDP. Also are you positive you want to use P2P? Question 30 is new apparently and covers some things.
Quote:Original post by Sirisian
Look at question 12 of the Forum FAQ for how quake and others do things.

It doesn't help that 2 of the 3 links in that FAQ are broken. :P (The other is 10 years old though I'm hoping that most of the principles still apply.)

I've read the links you posted and about quake... they basically send all object states every frame and use delta compression?

what happens if they run out of room to store everything in one packet, or is this a limitation they impose.

I think I'm getting mixed up about the server client model... would the server calculate everything such as the current frames in animation etc. and then send this to each client?

and what does the client send to the server, just the key/mouse input or more?
Quote:Original post by staticVoid2
I've read the links you posted and about quake... they basically send all object states every frame and use delta compression?


You delta compress in-memory, using the difference for each entity state between the ack state and the latest state, and you can compress that packet further with Huffman compression. Entities that haven't changed since the client ack number don't need to be sent. That means that the first state sent to a client (snapshot), will be much bigger than updates, since you need to send the base state of every entity in the game.

But since the sending is done during map loading, or can be throttled easily for clients joining games in progress, that's not a problem. Loading can take quite a while depending on the size of the initial game state.

Quote:what happens if they run out of room to store everything in one packet, or is this a limitation they impose.

No limitation is necessary. You can design a packet segmentation and reconstruction manually, it's not that hard. But you can use the UDP limit (64K) if you think your packets will never reach that limit.

Quote:
I think I'm getting mixed up about the server client model... would the server calculate everything such as the current frames in animation etc. and then send this to each client?

pretty much. Although the more dead-reckoning you can do on clients the better (basically, make educated guesses to save bandwidth.

Quote:
and what does the client send to the server, just the key/mouse input or more?

Commands usually. Not really inputs, but what the inputs should do (move left, move right, look towards (30, 123, 537), ect...).

Look at Gaffer's article on Networked physics as an example and case-study.

Everything is better with Metal.

thanks for all your help, I have one more question (if you don't mind)...

for data that remians fairly constant such as player names etc. would this data also need to be sent every frame?
Quote:Original post by oliii
But you can use the UDP limit (64K) if you think your packets will never reach that limit.
While 64K is indeed the protocol limit, routers tend to fragment anything much over about 1200 bytes, which makes large packets extremely unreliable over anything except a LAN.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Quote:Original post by staticVoid2
thanks for all your help, I have one more question (if you don't mind)...

for data that remians fairly constant such as player names etc. would this data also need to be sent every frame?


No, you only need to send static data like that when a new player joins the game:

- send the new player's static data to everyone in the game
- send everyone currently in the game's static data to the new player

Quote:Original post by staticVoid2
thanks for all your help, I have one more question (if you don't mind)...

for data that remians fairly constant such as player names etc. would this data also need to be sent every frame?


Nope. The static data would be part of the initial base state. However, since the data doesn't change, as soon as the client aknowledge the base state, that data does not need to be sent again (the delta compression will detect no change and will not send it).

This can work better if you 'lock' your update until the first state is aknowledged. If you can send the initial state reliably and wait until the client aknowledges it before sending further updates, you can 'throttle' the bandwidth and make sure you are not sending data more rapidly than your connection can handle (something TCP/IP does automatically, but you can roughly emulate that protocol through UDP).

But that's if you have a lot of static data with a large initial state. Say your initial state is 24K kilobytes in size, and if you limit your outstream bandwidth to an 4KBytes per client (16 clients -> 64kBytes outstream -> 512 Kbits outstream, what a pretty good DSL line could achieve), it could take up to 6 seconds to send that initial state to every clients. So it's not something to be sniffed at :)

Sending the initial state reliably can be as simple as sending each segment (say your UDP packets are 1200 bytes in size, and your state is 24K total, that will make about 20 segments) one after the other and repeat, until the client aknowledges that he received everything. Packet loss may mean some of the segments might get lost in the process, so you'll need to resend them.

It's not optimum, so it could take quite a while if you have lots of packet lost.

Everything is better with Metal.

thanks again, I have just one more question...

to trigger events over a network using this method I take it that the client would just need to recognise a state change in the udp packet and then call the appropriate function(s)?

for example if the udp packet had an integer informing the client of who currently held the flag in a capture the flag game and the current state of the flag...

struct Packet{   int flagState;   int flagHolder;};


then by checking the previous udp packet against the current one you would be able to tell if someone dropped the flag...

void Client::recv(UDPPacket cur){   switch(this->prev.flagState)   {      // the flag was previously being carried by a player      case CARRYING:      {         switch(cur.flagState)         {            // player dropped the flag            case DROPPED:            {               this->players[this->prev.flagHolder]->dropFlag();            }            break;         }      }      break;   }   this->prev = cur;}


Or would I be better to just send the position of the flag every frame and hide all object states etc. from the client?

This topic is closed to new replies.

Advertisement