3
\$\begingroup\$

Edit: My current system is going to be to send constant player updates every 1/20th of a second, each containing the player's status and position. I will also send another packet (or as many needed) every 1/20th of a second with the information of all the bullets, using this format to save space (the number representing the space in a packet):

1: Owner's ID
1: Type
1: Amount of bullets (so I don't have to include this info each time)

3: X coord
3: Y coord

I am currently writing a co op game to play at LANs, and have run into the issue of dealing with many entities and game updates. I only have implemented player movement, and the packets sent include the player's position for 3 ticks (as packets are sent and received every 3 ticks).

I have also implemented a system to keep track of the delay between client and server (sending the tick the server/client is at and comparing it to with the receiver's local tick).

This has worked thus far, however I have run into trouble with sending bullet information. It would be unfeasible to send the position of the bullet every update, as I would only have room for ~160 bullets + players per packet.

I thought of just sending the information that a bullet has been created and enough information for the client to simulate the bullet flying, such as velocity, angle, lifetime, and owner, and sending information when the bullet has been destroyed (via impact, lifetime, or otherwise). This got me thinking if it is possible to only send the keystates of a client to other clients via the server, to reduce the space required for co-ordinates and to increase smoothness of movement(floats will be used in this case instead of the current ints, as I have found difficulty transmitting floats).

This raises the concern of packet loss, and that with it the game could easily go out of sync. I have read of sending acks, however I am unsure if this will give me the wanted result. I have also read about sending a full game state ever so often, and this seems to me to be the best solution. What should I do to fix the issue of space and to reduce the space required for transmitting movement? And if it's the full game state solution, how often should I resync the clients? 5 seconds? 10 seconds? How do other games do it? I have read that the steam engine almost never does this, however it has many systems set in place to prevent packet loss and resending lost packets and I feel that I am unable to code all that.

\$\endgroup\$

3 Answers 3

4
\$\begingroup\$

First, don't send input-state.. send the computed output (eg, position and possibly velocity) instead. Keeping all participants in sync will be much simpler that way.

If you're just sending position, deltas aren't going to necessarily get you a smaller packet size. You're still going to have to send a 3 (or 2 for a 2D game) values, but the difference is that the origin is from the last guaranteed-known position. What this does get you is the ability for more precision in less bits.. the further from the origin you are, the more bits of precision you need to accurately represent a position, and it's more likely that a player is closer to its last position than to the scene's origin.

Unless your scenes are quite big, however, i wouldn't worry about trying to shave a few bits off there, and would stick to an absolute position with three floats, or the like.

Where I might shave things off if you're worried about bandwidth usage, however, is by having different messages for position vs. other state updates. As you start adding other state that needs to be synced between machines, send that extra data less frequently, and in a different message than your position updates.

As far as amount of space per-packet goes, I'd recommend not trying to fit everything in a single UDP packet. Send position, bullet creation, and other data as discreet messages, which are carried in UDP packets. (One message per packet is the simplest way to go, and probably the easiest to start with. If you find yourself sending lots of very small packets, you can optimize by batching up as multiple messages per packet later on.) Then, you can still send your position messages at a fixed rate, but you can send events like bullet creation as soon as they happen, instead of adding 3 ticks of latency to them.

"I have read of sending acks, however I am unsure if this will give me the wanted result."

If you're using UDP, you're going to need to implement some sort of acks or retransmission control for your game, as there are some messages you will need to make sure get through (eg, bullet creation). There are a number of networking middleware libraries that will implement this for you, but it's also not too hard to implement a basic version on your own.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks for the tips, I currently send 3 positions per server tick (since there are 3 normal ticks in one server tick) which takes up 12(x and y coords that are 2 big so their max is 62k) + 2 (player ID + packet type) slots. How can I convert from float to unsigned chars? Something like xvalue - int(xValue) * how many digits of precision I want to have and then just package that into chars? Also, I used to send position updates for each player in different packets, but that lagged up really quickly after about 7 players. \$\endgroup\$
    – user15498
    Apr 19, 2012 at 0:01
  • \$\begingroup\$ Well, you shouldn't need to send three positions for the same player - just send the latest. Between that and choosing a good interval for sending them, you should be able to handle much more than 7 players. (10 times a second should be fine.) As for conversion, just send the position coordinates as whatever datatype your game is using. (Tangentially: note that bits of precision is different from digits of precision. Take a look at how floats are encoded: en.wikipedia.org/wiki/IEEE_754-2008 for more info.) \$\endgroup\$
    – justinian
    Apr 19, 2012 at 0:25
  • \$\begingroup\$ I currently send at 20 times per second, but I think it'll be ok to send all types of the same data in the same packet. Also, the reason for sending 3 positions is so that I can make the movement seem smoother. I can interpolate between the current pos and the last known pos, but It'll look weird when the player is running into a wall but is moving slower because the distance between them and the wall is smaller than the usual traveled distance. Unless I set up a speed, hmm. Yes setting a speed should work. \$\endgroup\$
    – user15498
    Apr 19, 2012 at 0:31
  • \$\begingroup\$ sending only input state can be useful in some games in order to avoid cheating. it also make sure rules are always the same for everybody, even if client executable version or some scripts (eg : in a mod) differ from server version. however it is not always needed, especially if you want to keep everything simple. \$\endgroup\$
    – tigrou
    Apr 19, 2012 at 10:33
2
\$\begingroup\$

Delta's are a very very rare thing in networking in games as far as I can tell. They almost always run into syncing issues. Most of the time when you see a person do some funny sliding or the like, its not because a delta system is being used and then corrected at intervals. In general its because of a momentary packet loss of some kind, even if its just delayed data, and then a forced correction on top of the predictive side of the networking. So I actually suggest that you look into manners of packet compression as opposed to delta networking.

Some things to consider:

  • Only send updates for things that actually updated this frame.
  • Do send the updates right when they happen.
  • Consider some kind of bit packer. I personally recommend Arithmetic Encoders. The article here was very valuable in creating a couple of versions of these over the years. They work fairly well at compressing numerical data with out too much overhead processing.

I do want to once again caution against using a 'just send critical events' sort of system.. Every time I have dealt with a system like that it has caused a significant amount of effort to try and keep in sync and at the end of the day has always been changed into an exact system.

\$\endgroup\$
0
\$\begingroup\$

Concerning delta updates you have to do something like this:

  1. Send the latest gamestate (A)
  2. Store the current gamestate (A)
  3. next time you send an update you get the delta between the gamestate (A) and current gamestate (B)
  4. Store the current gamestate (B)
  5. When you receive an ACK for a gamestate you release all previous versions. ex ACK (B) release gamestate (A)
  6. When it's time to send the current gamestate (C) send the delta between (B) and (C)
  7. Store (C)

This is a single player scenario. You have to keep count of which gamestate is the latest version on which client. And you release all gamestates older than the latest one acknowledged by all clients.

There is data you should consider sending more often than other if you don't want to use deltas. Fundamentally the client apps must always receive data from the latest server tick about:

  • Current player positions
  • Changes on health/situation

They should receive as often as possible data about:

  • impacts and movement (animations) within perception range (visual and sound)
  • game objects visual/animation data.

If your bullets/projectiles are visible then the creation time, and data like type, position and direction are enough. Your client should know which type travels at which speed. Also you can do bulk updates ex:

30 new bullets created would become an array of [owner, time, position, direction] you don't need the type and other data as you can get those from the time created and owner. You must then also timestamp weapon switches.

If you still have trouble with packet sizes then compress the data sent from the server.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .