Position/movement synchronisation in a fast-paced 2d mmog

Started by
6 comments, last by Hyunkel 14 years, 5 months ago
Hello, I'm currently developing a small 2d mmorpg using Tcp for networking. I did position synchronistaion over a centralized server for another game some time ago, but it used a grid based coordinate system, and mouse input to target a cell you wanted to move to. This was quite easy, as a client only needed to tell the server it wanted to move to grid X, and the server would tell all clients in range, that player 1 is now moving to grid X. All clients in range would then move the sprite for player 1 from it's current location to grix X taking into account the player speed. Not only was this very easy to implement, but the networking was completely event based (there was no need to send position updates every x ms). However, my current game is a different animal. It's more of a hack&slash style game, meaning you are able to freely walk around using keyboard input. So there is no "target I want to move to" anymore, only a walking direction. I spend some time thinking about how to properly implement this, but I couldn't come up with a solution that I knew would work out. Here are a few ideas I came up with though: - Clients should only send a walking direction to the server. Maybe it would be sufficient to only send an update in walking direction if it actually changes, I don't think I need to do this every X ms, tcp should make sure the packet get's to the server. If a client has packet loss / lag though, this would cause them to keep running into the same direction until the delayed packet get's there. I'm not sure if this is a serious problem though, from experience network issues don't occur very often, and if they do, they're so bad it's unplayable anyways. - This is where I get lost, what should the server send to all clients in visual range? Say it just received from player 1, that he's running up now. What do I send to all clients in visual range? One possibility would be something like the playerid and direction.up only. The client would then make the player sprite with the given id walk up until it recieves something else. This would mean no real position checks though, so maybe the server should send a player position to everyone every time a player stops moving? Clients would check how far it is off from what they got, and correct if necessary (in this situation the sprite would jump though, and I see this happening rather often). Another possibility I thought of would be for the server to send the internal player position every x ms (if it changed) to players in range. The clients would then make the player sprite walk into the direction of the position they just received, and stop once they reach it. For some reason I don't see this working either. It shouldn't result in "jumpy" sprites, but it may result in an additional increase in delay, because the clients only get notified after a player has moved, and not once a player starts moving. I'm also not sure if this would result in fluid movement. I'm not even sure if I'm approaching this right at all, I've noticed that in some online games, your character starts moving the moment you hit a movement key, so the client is acting witout a server reply. I have no idea how they manage to keep that in sync. I'm assuming they don't treat the client who sends movement information the same way they treat observer clients. This may be what I actually want though, because in a fast-paced game with direct input (as opposed to clicking where you want to go), any kind of delay between hitting a key and your character moving will be somewhat annoying. Any insight on this would be greatly appreciated :) Hyu
Advertisement
I'll refer you to gaffer's article on client side prediction.

As for the lag compensation (to smooth out player movement on peers), you can look at this.

That involves sending regular position and direction updates of a player to everyone, so it's not cheap. In fact, that's the bulk of the traffic in FPS shooters.

Everything is better with Metal.

Thanks for the links, that was quite an interesting read.
I have a much better understanding on how some online games manage to appear to have no latency now.
Client side prediction is pretty much exactly what I was looking for.

I'll need to find an inexpensive way to keep peer movement smooth, just as you said.
I think I'll just go with regular peer position updates from the server, and make peer sprites walk towards those positions on the client.
Since I won't predict their movement, it should appear rather smooth, but they will obviously lag behind.
However I don't think this is problematic for this specific game, it doesn't really matter if I see other players a few ms "in the past, so to speak", as long as I have a good idea where I'm standing myself.

Thanks,
Hyu
After trying a few things, I managed to get it to work, using something similar to the Client side prediction method posted.

I made it so that when a character stops moving, it doesn't just immediately freeze, but it gradually gets slower until coming to a stand.
This obviously happens very fast, we're talking about ~200ms here at most, and gives the client enough time to smoothly sync the position with the server.

For this to work I need to send movement packets every 100ms though (only if movement occured), which brings me to my next question :)

My current position update packet looks like this:
[byte packettype][byte direction im facing][int x][int y] (this goes into a binary stream which I send to the client)

so, this is a rather small packet, but, considering the current size, how many packets a second are considered to be too much?
I mean, it's an mmo after all, so it needs to be able to cope with alot of players running around at the same time.

Is 10 packets a second ok?
Should the server send movement packets separately for each peer a client sees, or should it send a list of movement updates in a single packet instead?
Quote:Original post by Hyunkel
Should the server send movement packets separately for each peer a client sees, or should it send a list of movement updates in a single packet instead?

Personally I consider any system that thinks in terms of "movement packets" to be broken. I'd use "movement messages" which I push to the networking code, and that will often place several messages into one packet before sending. You're not going to be able to scale to 'massive' if you're not already buffering your data on the way out anyway, so take advantage of that buffering system to reduce the number of packets you send.
Quote:Original post by Kylotan
Personally I consider any system that thinks in terms of "movement packets" to be broken. I'd use "movement messages" which I push to the networking code, and that will often place several messages into one packet before sending. You're not going to be able to scale to 'massive' if you're not already buffering your data on the way out anyway, so take advantage of that buffering system to reduce the number of packets you send.


Sorry, yes, that's what I'm doing, I phrased my question rather poorly, and calling such a network message "packet" sure didn't help :P

What I wanted to ask is (which is better?):
1) should the server send a list of moved peers to each client, say, every 100ms (every position is updated at the same time)
2) or should the server immediately send a movement message to all clients in range, as soon as it receives an update from a client (after verifying it is legit of course)

Currently I'm using method 2) because I'm afraid 1) would result in a burst of packets being sent every 100ms, causing a peak in bandwidth usage, wheras method number 2) will send packets out smoothly.
But since this is the first time I'm writing networking code for a real game, and not a prototype / proof of concept, I prefer to ask, because I'm rather inexperienced.
Quote:Original post by Hyunkel
Sorry, yes, that's what I'm doing, I phrased my question rather poorly, and calling such a network message "packet" sure didn't help :P

What I wanted to ask is (which is better?):
1) should the server send a list of moved peers to each client, say, every 100ms (every position is updated at the same time)
2) or should the server immediately send a movement message to all clients in range, as soon as it receives an update from a client (after verifying it is legit of course)


For performance and scaling you should send updates to clients at a constant rate and combine similar messages into a single variable length message (choice #1). For example, say you are sending movement updates for N players to a specific player. Using your message layout above, the message would look something like:

[byte packettype]
[byte numberOfPlayers]
[byte directionPlayer0][int x0][int y0]
[byte directionPlayer1][int x1][int y1]
...
[byte directionPlayerN][int xN][int yN]

The client will read the message type, then read how many player updates are in the message, then parse the N player updates from the message.

Quote:Original post by HyunkelCurrently I'm using method 2) because I'm afraid 1) would result in a burst of packets being sent every 100ms, causing a peak in bandwidth usage, wheras method number 2) will send packets out smoothly.
But since this is the first time I'm writing networking code for a real game, and not a prototype / proof of concept, I prefer to ask, because I'm rather inexperienced.


Actually, with a non-trivial number of players, #2 would likely consume more bandwidth because the messages are small and sending them individually will add to a lot of wasted bandwidth due to TCP/IP headers on the messages.
Makes sense, I didn't consider overhead.
Thanks for your input :)

This topic is closed to new replies.

Advertisement