Multiplayer networking newbie

Started by
22 comments, last by Hayer 13 years, 5 months ago
What engine and network library are you using?

Im using C# + XNA + Lidgren 3.

Well, gonna give those a little try. What did you mean with "sliding" instead of "teleporting"?
Advertisement
I have done what I said in c++ with networking library ENET.
Imagine your latency is too high like 1 second then you'll see other clients teleporting because the actual position and predicted position is 'very' different you can add something like offset variable which is a point. And instead of teleporting add the teleporting distance we have found to this offset.
When uptading, with addition to speed add i.e. 10 percent or 5 percent or 50 percent of this offset to players position :) i am not sure but you can experiment. I never had to 'slide' teleporting worked fine for me because i only tested it with 3 players pings were okey.
Another question;

You say; when the client receives a client-move byte from another client - you mean client->server->another_client, right?

But, when the server receives a "kill-move"-byte I have to calculate the latency for that to? And then the player will "snap" a few pixels back?
Quote:Original post by stonemetal
What kind of player count are you planing on handling? That kind of send player actions + lag compensation is typical of FPS games with 16 to 32 players.


You must be an experienced programmer if you use "round" numbers such as 16 and 32 ;-)
------------------------Computers do what you tell them to do, not what you want them to do.
Yes I meant that. There are two or three ways I can think of, most basic is to let every client know everyone elses pingtime with the server. So you can add your and his pingtime product with his speed, add to offset if he started and substract from the offset if he stopped.

Other method would be, which I had used, is very precise synchronising the timers for all clients & server. This way clients dont have to care about pingtimes of all other clients.which is actually 'dumb'. Then You can just timestamp events and you get the difference between timestamp-read and current time. But the hard work here is precise synchronising many clients with server. 100ms difference may ruin your game. I guess.

I can try to explain how to synchronise if you cant find it
Okey, so I've done some of my homework now - I read up on the "Valve Source Multiplayer Networking"

So I'll just post what I wrote as "notes" to my self - It would be nice if anyone could confirm my notes ;p

// START OF COPYPASTE

* ticks per sec - simulations per sec (server)
* each tick
- process incoming user commands[1]
- run physical simulation
- check game logic / rules
- update all object states

[1] User command
The client creates user commands from sampling input devices with the same tick rate that the server is running.

NOTE:
Instead of sending a new packet to the server for each user command the client sends command packets at a certain rate of packets per sec(30[2] standard) -> two or more user commands are transmitted within the same packet.

[2] Update rate
Client-side variable(called cl_cmdrate in Source Engine) decides how many samplings per sec. Higher cmdrate -> more out-bandwitdh needed.

Snapshots sent to client per sec i decided by the client variable(cl_updaterate in Source Engine) witch is sent to the server
NORE: For dev. and keeping it simple this is set to 20.

The server keeps the last 100 snapshots so when a client fire-command is received it that rewind back in the snapshots and see if the bullet hit anyone.

// END OF COPYPASTE

One of the main things I'm wondering about is; how should I save the 100 last snapshots? That would be pretty large array if I saved ALL object.

( sizeof ( player ) * number of players + sizeof ( zombie ) * number of zombies ) * 100?
Quote:The problem is that there is so many ways to do it!
I only want a simple way that still gives a good result compared to how hard/long time it takes me.


Instead of "networked game," compare "strike it rich."

There are many ways to do it. All I want is a simple way that still gives good results without having to work too hard/long. :-)

In reality, this is *hard*, no matter how you do it.

"Source" (or "Quake" or "Unreal" or "Entity State") style networking is great for FPS-style games with a small number of actors.
"Age of Empires" (or "Starcraft" or "Input Synchronous") style networking is great for minimizing networking when you have tons of actors, but is more complex to get right.

You have to look at your goals (N entities, M updates per second) and your available resources (Q megabytes of memory, Z bandwidth per player) and choose one that fits your requirements.
For example, 100 snapshots for 1,000 entities isn't that much, if each snapshot is 100 bytes. It's just 10 MB. On a PC or modern console, that's nothing, and you might even be able to afford it on the bigger cell phones.
enum Bool { True, False, FileNotFound };
I was thinking of using entity state for the players and and simplified RTS approach for the zombies.

Or is that just a bad idea?

My main problem is understanding what formulas should be used at the server and what formulas that should be used in the client to synchronize them as good as possible.
I understand mostly of the theory(at least I think so), but I don't know how to code it.
I guess I'll just have to get to work and try different things.

One thing that came to my mind is;
in the source engine they "rewind" the player positions by saving the 100 last ticks - how would I do that with the zombies? only save they're position and unique ID in a array? That way the array will only take ( sizeof( Vector3 ) + sizeof( Int ) ) * 100
Okey; did some simple testing and math now;

And I tought; okey, if I only store the players and the zombies positions for the last 100 snapshots and I got a total of 200(players + zombies) that would be;

((sizeof(float)*3 + sizeof(int))*100*200

sizeof(float)*3 = Vector2 + the rotation vector.

That would be 320mb for only the 100 last snapshots. If I then add 75mb for a map and 25mb for other things I havnt tought about yet that would be 420mb for a server.

Thats right.. or? >_>

I wouldn't call that much memory for a game server - or am I totally lost?

Erlap;
You would mind explaining some more about how you synchronize the timers and stuff for all clients and the server?

And; ping is never constant, its always changing - so going with your first approach you.. do what? tell the ping to every client every 10sec or something like that?
I didn't get what you are calculating.. aren't you making a 2d-game?
you can store 2 bytes for x location 2 bytes for y location and one byte for rotation. I don't think you can see the difference for 360/256 degrees, which will be your max round-up error with rotation. anyway in case you want to be more precise store 2 bytes for it too and all should be OK if I am not mistaken.

You can even send ping-time to clients every second.. Or observe the oscilating clients and check them more often while omiting the constant-staying ones, if you want to optimize bandwidth.
Suppose you have 10 players, 2 bytes is enough for one ping-time, which shouldn't be over 6500 hopefully :P. every player will get 10 ping-times, which is 20 bytes and TCP header which is 20 bytes too. 40 bytes/sec is just too small for me. and for server it is 400 bytes/sec upload. Oh 400 is much for just ping-times. You can either switch sending ping-times rarely or using synchronised timers.

I'd explain how I did it but you started to get complex for me with that storing snapshots idea.Anyway you can synchronise all the timers like this:

Suppose A is server and B,C,D... are clients respectively.

1)Set A to synchronising state.
2)Start the timer on A and send all the clients a ping-packet(which can be either empty or equal to avarage size of the packets you'll use during your game)
3)Now clients will start getting packets, as soon as each one gets, resend the data to server and start their timers.
4)As soon as server gets the data resend the packet again..
5)As soon as a client now gets a data increase their ticks by 50 percent and wait till the synchronising state is over.

This works because the timer-difference at the beginning is packet travel time (difference between 2 and 3). After starting the timer on a client you ping-pong a packet and thats a whole 2 ping-time. And you add the difference which is only the half of that.I don't know if its the best solution but it has WORKED for me :)

This topic is closed to new replies.

Advertisement