views:

707

answers:

6

I'm thinking of creating a web multiplayer game in Node.js. This means I'll be using the same language in the backend and in the frontend. It would be in realtime and about 20 people max in each 'room', so I have a few thoughts:

  1. How do I compensate for the delay among all users so that everyone sees the same thing the same time? I'm thinking of tracking the average ping time of each player, find the slowest one, and inform the other clients of the ms they have to be delayed each one so that everyone is as sync as possible.

  2. I'm thinking of running the game code in the backend as well as in the frontend (since it's Javascript on both ends) and just have an error-correction mechanism to synchronize with the 'real game' in the backend. That way the game should perform smoothly on the frontend and with only few glitches when the sync happens. Also that would minimize frontend JS hacking since cheaters would be synced down to the backend game.

  3. Should I receive player actions through the socket (keypresses), inform all other clients of the other players' actions and in the mean time 'playing' the game in the backend and send a sync to everyone of the entire game state every once in a while to sync them?

What do you think? Are there more stuff I should consider or pay attention to?

Please post any thoughts or links to documentation or articles regarding multiplayer gaming.


EDIT: These are useful:

+1  A: 
  1. This one is very hard to do, and I can see lots of problems with syncing to 'the slowest'. Can you loosen this up so the clients could be 'eventually consistent'?

  2. Sounds good.

  3. I would send short action events from front ends to backend, have the backend modify game state and publish game state modification events back to the clients, with much attention to only sending the necessary events out to the right subscribers. At this point you can discard any events that don't seem to match or that seem like fakes/hacks.

Santi
Can you elaborate on 'eventually consistent' ? I have at least 1 object that everyone should see in the right place at the same time, or the game wouldn't work, I don't really care about everyone seeing everyone at the same place/time, but one or two objects can't be out of sync or the game will fail. ( who can guess the game first? I've given a few hints :P )
stagas
Just meaning that the events sent in 3) from the backend would not arrive synchronously to all the clients (quite impossible). Maybe you could have the clients report to the server when they have received a particular object, although this might make way for cheating.
Santi
@stagas: will there be 22 people in the room? :)
Amnon
@Amnon: 20, the goalkeepers are AI :)
stagas
+11  A: 

1 - is impossible. You don't know exactly how long a message will take to arrive on a client and no measurement you take will necessarily be applicable to the next message you send. The best you can do is an approximation, but you always need to assume that people will see EITHER slightly different things OR the same things at slightly different times. I'd recommend just sending the current state to everybody and using interpolation/extrapolation to smooth out the gameplay, so that everybody sees the game a few milliseconds in the past, with the delay varying both between players and over time. In general this is rarely a big problem. If you really want to buffer up some past states on the server you can interpolate between them and send different old data to different people in an attempt to sync what they see, but combined with the client side simulation and the jitter in transmission times you'll still see some differences across machines.

2 - the typical way is to run the simulation on the server, and send regular (small) state updates to clients. Clients typically run their own simulations and have a way to blend between their own predicted/interpolated state and the authoritative state that the server is sending them. All decisions other than user input should be made server-side. Ultimately the way you blend these is just a tradeoff between a smooth appearance and an accurate state so it's a cosmetic decision you'll have to make.

3 - your client should typically translate a keypress to a logical action. Your server doesn't care about keys. Send that logical action to the server and it can broadcast it to other clients if they need it. Generally though you wouldn't need to do anything here - any relevant change caused by the action will typically just change the game state, and thus will get sent out in the normal broadcast of that state.

Kylotan
A: 
  1. Does everybody need to know the others actions, all the time? The more players there are the more critical it becomes to be able to evaluate exactly what each player needs to know about its surrounding area. Players located very far away are likely to have no consequences regarding whats going on where you are. Massive amounts of data sending and lag can be saved by having a good evaluation on relevance.

I have made the beginning of a javascript game here:
http://hermanningjaldsson.com/games/tank_fight/9/
For a debug free mode just change the version number in the url from 9 to 8.
Feel free to copy the game code, just keep credits of who did it.

When you drive the tanks around you can see how i am trying to evaluate relevance to each tank. Each tank monitors all tanks every so-and-so seconds. If, a tank is very far away, it just stays at checking the distance to it at this slow rate. If on the other hand, the other tank has come within a certain distance, it enters another array, which is checked much more frequently. and if it comes closer still, it enter the 'is_within_range' array. that array is continuously checking if there is a collision. Thats a much more expensive check than just a distance check every 10 seconds(by around a factor of 10.000).

I also remember speaking to a guy who said some system named 'comet' was very good for multplayer javascript realtime gaming.

When working on this tank_fight game i found the raphael library very useful. It allowed me to use svg without having to worry about non ie browser idiosyncrasies.
http://raphaeljs.com/
I just skipped Internet Explorer completely since I'm running on Linux and didn't have access to it and also because it didn't seem to respect w3c standards.

I also recommend having a requirement for entering the game that the connection is so and so fast. A single user with an abysmal connection can damage the game for everyone.

Hermann Ingjaldsson
Yes, prioritizing the data is a good way to improve the speed by reducing the number of messages that need to go through the network.
stagas
+3  A: 

I won't address your points directly because the other answers do so well. But, I suggest looking into HTML5, WebSockets, and Comet which promise to significantly improve realtime performance. These technologies enable you to have long-running HTTP requests, allowing the server to push data to the client rather than the client polling the server. This can substantially speed things up.

Here are some resources that should prove useful:

Tauren
Thanks, I added Socket.io also which is a WebSockets implementation with a server and a client that fallbacks to other technologies if one is not available. Very useful.
stagas
A: 

One typical approach is not to try and force all clients to run at the same FPS locked to the server... it just gets ugly. Instead, send frequent updates so clients can update whenever they receive a new update.

Normally, a client will predict how things are going for short periods, then be corrected by an update from the server. You can apply time corrections too e.g if the server tells you "player 2 is at P travelling at velocity V" you can make some attempt to know how old that message might be based on recent ping, and correct the position from P to P+x*D

John
A: 

The best way is to keep track of all objects in only one place, namely the server. Everyone will see the information from the servers one travel time later than it "actually happens" and people's commands will take one travel to register on the server. There really is no way around this. For some applications it can be practical to simulate your own movement right away without waiting for a server response but this will undoubtedly lead to a nightmare with the timing programming and people will typically see each other "lagging around". Collision detection is all but impossible.

The net effect of this is that there will be a sluggishness from when you enter your commands until you see them actually happening but hopefully people will learn to cope with this and try to input their commands slightly earlier to compensate. With slow connections fast-paced realtime games is just impossible.

MatsT
From what I've seen so far this is what everyone is trying to avoid. Sending the message to the server and waiting for the server to acknowledge will result in very laggy movement. The workaround is to render the movement instantly, send the message to the server and let the server 'move forward' in order to compensate for the lag. The only problem is when you constantly change directions and do lots of actions in little time but still the local response should be instant and apply corrections only when the server disagrees otherwise it's no good.
stagas
That's exactly my point, it will not work at all for a fast-paced collision-based game. If you change direction the other players will still see you moving for ~1 roundtrip before warping to the new location. But I guess that IS how games like Counterstrike work. Still doubt it will work out in a game like soccer.
MatsT
That's fine, you suggested that the server has control of local movement which is not a desired effect. Messages can be prioritized, i.e. for soccer the person that holds the ball, should be the one making the choices, and make it hard for the defenders to get the tackling right is what will probably work for me. You can't have everything, just make it as less painful as possible. It'd suck if you were about to shoot and you had to wait for the socket roundtrip to actually shoot. It should be instant, and the server should obey because you hold the ball. It's a defender's problem so it's ok ;)
stagas