[ENet-discuss] Best practises for synchronizing states

Nicholas J Ingrassellino nick at lifebloodnetworks.com
Thu Nov 25 22:14:13 PST 2010


The client sends keys presses reliably to the server. It does not send, 
for example, a fire event or some such thing. The server is responsible 
for deciding what key does what.

The server only has code to synchronize objects with the clients. In my 
game I have a global ("global" as in it applies to all clients equally) 
array which assigns each object a number. I also have an array of equal 
size per client. These two arrays are compared to see which objects the 
client has been notified about. It sends these messages (create, remove) 
reliably. The rest of the time it just send data about these objects 
unreliably. One thing to watch out for is to make sure the client finds 
out an object exists before it gets updated. Other wise things explode 
in such a way that is very hard to debug. On the same token make sure a 
client does not get updates about an object that has been removed.

The down side of this system is that it can be *very* venerable to 
latency _if not properly balanced and tested over different kinds of 
connections_. I spent a week figuring out what worked and did not work 
over cable connections, 10Gb fiber LAN, and my mobile phone. The up side 
is that is it a very generic way to do things and allows me to spend 
100% of my time on the game; The server worries about when and how to 
send updates without me handling special cases every time a player 
sneezes. The client monitors an array object and blindly displays what 
it finds. The server updates the client on a need-to-know basis. Another 
up side is this can help keep cheating down in some situations (IE the 
server does not send information about objects a player can not "see").

My game is a fast-paced, top-down shooter (speaking of generic...) so 
the players never really stop moving if they want to have a chance at 
survival. Once moving I use simple dead reckoning to keep them moving 
until the next update. You could easily add some code that starts the 
player object moving at a certain speed before the response is received 
from the server and then continue normally (IE replace the object x, y 
with what the server sent). I, however, did not find that necessary and 
it would require the client being aware of more things (for example, 
what key does what) than I am already doing in my project.

As I implied, my client is virtually a dumb terminal with this system. 
As a matter of fact, the stripped-down client code is something like 25% 
of the stripped-down, only required server code.

Hope all this helps. It is not the most advanced system but it works 
great for me and is an excellent entry-level exercise. Try to think less 
in terms of what events should be sent reliably and unreliably. "Bullet 
fired" and "player moved" are just abstractions that make a machine that 
does lots of math look like pretty, coherant images. Instead focus on 
the flow of data and what experimenation leads you to and the code will 
write itself.

------------------------------------------------------------------------

Nicholas J Ingrassellino
LifebloodNetworks.com <http://www.lifebloodnetworks.com/> || 
nick at lifebloodnetworks.com <mailto:nick at lifebloodnetworks.com>

"The idea that I can be presented with a problem, set out to logically 
solve it with the tools at hand, and wind up with a program that could 
not be legally used because someone else followed the same logical steps 
some years ago and filed for a patent on it is horrifying."
- John Carmack on software patents


On 11/24/2010 09:27 PM, Philip Bennefall wrote:
> Hi Nicholas,
> So you send key presses reliably, and then wait for the server to 
> respond back with a new state? What happens if a player fires their 
> weapon, for instance, is this sent reliably? I guess my main confusion 
> is what should and what should not be reliable traffic. It would make 
> sense to me that gunshots were reliable, where as individual movement 
> steps could be sent unreliably as you say. Now let's say that the 
> client takes a step, do you then render the movement animation 
> immediately before you get the response back from the server and then 
> correct it if the server refuses, or do you wait for the server to 
> accept the move? If the former, what happens if the client moves but 
> he's not allowed to, do you just silently bounce him back? If the 
> latter, wouldn't there be a noticeable delay between the key press and 
> the actual movement since we need at least one roundtrip for that?
> Kind regards,
> Philip Bennefall
> ----- Original Message -----
>
>     *From:* Nicholas J Ingrassellino <mailto:nick at lifebloodnetworks.com>
>     *To:* Discussion of the ENet library <mailto:enet-discuss at cubik.org>
>     *Sent:* Wednesday, November 24, 2010 6:23 PM
>     *Subject:* Re: [ENet-discuss] Best practises for synchronizing states
>
>     I question if the lag is as bad as you are expecting it to be.
>     Some connections and/or rural areas are worst than others but I am
>     not sure it will be as bad as you think. For example, if you look
>     back at the last few e-mails I sent to this list you will see my
>     current project treats the client as a dumb terminal-- only key
>     presses are send and object information is back unreliably 20
>     times a second. There is some dead reckoning (the object speed and
>     direction are sent to the client and the client does that work
>     while waiting for the next update) and I do not have an issue even
>     on my mobile phone.
>
>     My point is you should run a number of tests to see what you get.
>     Make sure to play with the rate the "server" (or in your case
>     client to client) sends data vs bandwidth usage. Make sure you do
>     not flood the line with too many tiny packets and that you process
>     all packets in a while loop (vs an if) to make sure you processes
>     everything as fast as possible. Another note on my project is that
>     I do not wait on an timers to process network events (as opposed
>     to my log and display code that only happens 60 times a second).
>
>     I think you may surprised yourself with what you can pull off in
>     terms of latency.
>
>     ------------------------------------------------------------------------
>
>     Nicholas J Ingrassellino
>     LifebloodNetworks.com <http://www.lifebloodnetworks.com/> ||
>     nick at lifebloodnetworks.com <mailto:nick at lifebloodnetworks.com>
>
>     "The idea that I can be presented with a problem, set out to
>     logically solve it with the tools at hand, and wind up with a
>     program that could not be legally used because someone else
>     followed the same logical steps some years ago and filed for a
>     patent on it is horrifying."
>     - John Carmack on software patents
>
>
>     On 11/23/2010 10:00 PM, Philip Bennefall wrote:
>>     Hi all,
>>     This is a fairly lengthy email, so I apologize in advance.
>>     I am relatively new to ENet. I have integrated it in my game
>>     engine and have successfully written a game which is working
>>     perfectly. It is one of those finger twitching action games where
>>     speed is of the utmost importance and delay is the most evil
>>     thing in the world. The way I do it is to keep sending the entire
>>     state for a player to the other party unreliably. The other
>>     client then works out the events that "must" have occured by
>>     looking at the differences between the last known state and the
>>     new one. This is far from a perfect solution as it neither scales
>>     well nor provides for very readable code. Here's a summary of how
>>     I'm handling things:
>>     The game is a shooter where you run a round on a 1d grid firing
>>     rocks at your oponent's palace. When a rock hits a square on the
>>     other side it'll quickly begin piercing its way through until
>>     that section of the wall crumbles. During that time, the other
>>     player may use their hammer to defend the section.
>>     I wrote an internal layout description for myself before I
>>     started coding, which I then followed to ensure proper handling
>>     of all possible situations.
>>     ---Start of Internal Description---
>>     The way in which this game communicates over the network is
>>     fairly simple. The two players have a direct connection
>>     established between one another, and they send out their player
>>     state roughly 30 times a second. This player state contains the
>>     current x position, the current throwing position which is -1 if
>>     nothing is being thrown, and then a list of all the squares on
>>     that player's side. For each square, two values are stored. The
>>     first is the current resistance which is 20 on max, and 0 if the
>>     square is destroyed. The second one is crumbling speed which is 0
>>     if the square is not currently crumbling, and a value in
>>     milliseconds otherwise. This value is used to measure if two or
>>     more rocks have been thrown on the same square.
>>     When a new state is received from the remote player, we have to
>>     analyse this information in order to determine what changes that
>>     have occured and if we need to take any action.
>>     If a new x position is received, we simply move the player's
>>     local variable to this square and play a footstep sound.
>>     If the new throwing position is different from our old one, we
>>     can take a few actions depending on its value:
>>     1. If the new one is greater than -1 and the old one is -1, the
>>     remote player threw a rock at us. we play the throwing sound in
>>     the appropriate location, but take no other action.
>>     2. If the new one is -1 and the old one is greater than -1, we
>>     can assume that the remote player hit us and start the crumbling
>>     sequence for that square on our end. Naturally if our square is
>>     already crumbled, the remote player will not get any hit
>>     notifications from us.
>>     3. If they both are greater than -1, we can assume that the
>>     remote player hit us and so we activate that sequence as above.
>>     We can also assume that the remote player made a new throwing
>>     attempt in another location and that we didn't see the -1 state
>>     that came prior to it probably because of lag, and so we play
>>     another throwing sound in the new location.
>>     After this, we go on to scan the game board and do the following
>>     for each square:
>>     If the new resistance is greater than the old one, the remote
>>     player hammered and so we play that sound.
>>     If the new resistance is lower than the old one, we can take four
>>     actions.
>>
>>     1. If the new resistance is 0 and the old resistance is greater
>>     than 0, the square just broke so we play the appropriate sound
>>     and forget about it.
>>     2. If the old crumbling speed is the same as the new one, this
>>     was a normal crumbling step and so we play the appropriate sound.
>>     3. If the old crumbling speed is 0 and the new one is greater
>>     than 0, this was a new hit so we react accordingly.
>>     4. If the old one is greater than the new one and the new one is
>>     greater than 0, this was a new hit on the same square.
>>     ---End of Internal Description---
>>     I realize that this is a lot of very game specific information,
>>     and that's exactly my point. This all seems like a very dirty
>>     hack to me, and I was wondering if any of you can suggest a
>>     better and more scalable way of doing this while still keeping
>>     latency to an absolute minimum?
>>     Thanks in advance for any help!
>>     Kind regards,
>>     Philip Bennefall
>>     P.S. I should perhaps mention that this is a game for the blind;
>>     entirely based on sound, which is why sounds are mentioned all
>>     over the place rather than graphics.
>>
>>
>>     _______________________________________________
>>     ENet-discuss mailing list
>>     ENet-discuss at cubik.org
>>     http://lists.cubik.org/mailman/listinfo/enet-discuss
>>            
>
>
> _______________________________________________
> ENet-discuss mailing list
> ENet-discuss at cubik.org
> http://lists.cubik.org/mailman/listinfo/enet-discuss
>    
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cubik.org/pipermail/enet-discuss/attachments/20101126/bc11dd72/attachment-0001.html>


More information about the ENet-discuss mailing list