I'm wondering what's the best way to to implement the networking model for a game like agar.io - I'm assuming it's an authoritative server, but I'm wondering about:
Does every player "owns" his position, and sends it to the server, or does every player merely sends his input and everything is fully authoritative on the server?
How does it decide what data to send to which player? I'm assuming that for every player I would have to iterate on all players in the server and check if they are currently (or soon to be) visible, and if so begin sending data on them
Where do the actual collisions happen, and how to handle lag?
I'm well aware of the ways to handle this in an FPS game (player prediction, rewind replay, lag compensation, etc) - but it's usually done on a much smaller scale, and I assume a simpler solution is good enough for a casual game like that with thousands of concurrent players.
the model in agario is shown by 2 things:
You can see other players eating the same dots, so that shows the players are receiving the positions of all players (probably around 5 times a second) and then the dots appearing and disappearing are handled client side. If the dots weren't handled client side that would cost huge bandwidth. That also means that you receive a message containing positions of all dots on startup, which makes sense because not all the dots are there in the beginning
The inputs from players to server are sent as opposed to positions, because otherwise it would be extremely hackable. The logic for collisions are then handled on the server
If the other player's inputs were broadcasted (instead of positions) from the server to the clients after the server got them small differences would build up like the butterfly effect and cause chaos
I'm pretty sure the inputs are only sent 5 times per second because there's a problem with websockets that causes packets sent more than 5 times per second to be clumped together
Related
I'm making an iPhone game that runs at 50 fps per second. I'm thinking of implementing multiplayer in my game using Game center. But first I have a question how fast I can send data using gamecenter. I will only send a struct with three floats. Is it possible to send data fast enought to make me receive data every 20ms (1/50)?
It could at best take around 15 milliseconds send data.
The only thing you can depend on when sending stuff across the network from a mobile device is that the connection will be slow and intermittent.
If you assume anything else then you will run into problems.
You should always program for the case where the data takes a "long" time to come through and may not come through at all.
For instance, if you're making a real time multiplayer game then have some way of the opponents character moving in a "best guess" way until the next bit of data comes up. Etc...
Also, your games should be running at 60fps not 50.
I'm writing a FPS XNA game. It gonna be multiplayer so I came up with following:
I'm making two different assemblies — one for the game logic and the second for drawing it and the game irrelevant stuff (like rocket trails).
The type of the connection is client-server (not peer-to-peer), so every client at first connects to the server and then the game begins.
I'm completly decided to use XNA.Framework.Game class for the clients to run their game in window (or fullscreen) and the GameComponent/DrawableGameComponent classes to store the game objects and update&draw them on each frame.
Next, I want to get the answer to the question:
What should I do on the server side? I got few options:
Create my own Game class on the server, which will process all the game logic (only, no graphics). The reason why I am not using the standart Game class is when I call Game.Run() the white window appears and I cant figure out how to get rid of it.
Use somehow the original XNA's Game class, which is already has the GameComponent collection and Update event (60 times per second, just what I need).
UPDATE:
I got more questions:
First, what socket mode should I use? TCP or UDP? And how to actually let the client know that this packet is meant to be processed after that one?
Second, if I is going to use exacly GameComponent class for the game objects which is stored and processed on the server, how to make them to be drawn on the client? Inherit them (while they are combined to an assembly)? Something else?
First of all, your game logic should be on the server.. Not only does that prevent cheating, but it also garantees consistency, especially over random operations. The clients should only be sending their inputs to the server
I'd recommend your keep the server's window visible to make it a debug console, you'll need it, to know what your server is doing exactly.
For a FPS, UDP is recommended. You'll be sending a lot of data and you don't really care if your packets are all received or ordered. While the packets are not garanteed to arrive ordered, you don't really have to worry about it. Most of the time, they will arrive in order anyway. Let's say you send 60 frames per second to your clients and one of your packet arrives in the wrong order: Your client will have erroneous information for 1/60th of a second, which is barely visible.
Finally, you should send a serialized representation of your game state multiple times per second to your clients. They should be able to retrieve that information and draw it the same way as your server. You could even serialize your gamecomponent and send it if you think that's appropriate. It's really up to you to decide.
Hope this helps!
For security reasons I have a feeling that that testing should be done server side. Nonetheless, that would be rather taxing on the server, right? Given the gear and buffs a player is wearing they will have a higher movement speed, so each time they move I would need to calculate that new constant and see if their movement is legitimate (using TCP so don't need to worry about lost, unordered packets). I realize I could instead just save the last movement speed and only recalculate it if they've changed something affecting their speed, but even then that's another check.
Another idea I had is that the server randomly picks data that the client is sending it and verifies it and gives each client a trust rating. A low enough trust rating would mean every message from the client would be inspected and all of their actions would be logged in a more verbose manner. I would then know they're hacking by inspecting the logs and could ban/suspend them as well as undo any benefits they may have spread around through hacking.
Any advice is appreciated, thank you.
Edit: I just realized there's also the case where a hacker could send tiny movements (within the capability of their regular speed) in a very high succession. Each individual movement alone would be legite, but the cumulative effect would be speed hacking. What are some ways around this?
The standard way to deal with this problem is to have the server calculate all movement. The only thing that the clients should send to the server are commands, e.g. "move left" and the server should then calculate how fast the player moves etc., then finally send the updated position back to the client.
If you leave any calculation at all on the client, the chances are that sooner or later someone will find a way to cheat.
[...] testing should be done server side. Nonetheless, that would be rather taxing on the server, right?
Nope. This is the way to do it. It's the only way to do it. All talk of checking trust or whatever is inherently flawed, one way or another.
If you're letting the player send positions:
Check where someone claims they are.
Compare that to where they were a short while ago. Allow a tiny bit of deviation to account for network lag.
If they're moving too quickly, reposition them somewhere more reasonable. Small errors may be due to long periods of lag, so clients should use interpolation to smooth out these corrections.
If they're moving far too quickly, disconnect them. And check for bugs in your code.
Don't forget to handle legitimate traversals over long distance, eg. teleports.
The way around this is that all action is done on the server. Never trust any information that comes from the client. If anybody actually plays your game, somebody will reverse-engineer the communication to the server and figure out how to take advantage of it.
You can't assign a random trust rating, because cautious cheaters will cheat only when they really need to. That gives them a considerable advantage with a low chance of being spotted cheating.
And, yes, this means you can't get by with a low-grade server, but there's really no other method of preventing client-side cheating.
If you are developing in a language that has access to Windows API function calls, I have found from my own studies in speed hacking, that you can easily identify a speed hacker by calling two functions and comparing results.
TimeGetTime
and...
GetTickCount
Both functions will return the number of seconds since the system started. However, TimeGetTime is much more accurate than GetTickCount, whereas TimeGetTime is accurate up to ~1ms vs. GetTickCount, which is accurate at around ~50ms
Even though there is a small lag between these two functions, if you turn on a speed hacking application (pick your poison), you should see a very large difference between the two result sets, sometimes even up to a couple of seconds. The difference is very noticable.
Write a simple application that returns the GetTickCount and TimeGetTime results, without the speed hacking application running, and leave it running. Compare the results and display the difference -- you should see a very small difference between the two. Then, with your application still running, turn on the speed hacking application and you will see the very large difference in the two result sets.
The trick is figuring out what threshold will constitue suspicious activity.
When I was writing a simple server for a simple client <> server multiplayer game, I thought of the following text-based protocol using a translation library. Basically, each command had a certain meaning, eg:
1 = character starts turning right
2 = character starts turning left
3 = character stops turning
4 = character starts moving forward
5 = character stops moving
6 = character teleports to x, y
So, the client would simply broadcast the following to inform that the player is now moving forward and turning right:
4
1
Or, to teleport to 100x200:
6#100#200
Where # is the parameter delimiter.
The socket connection would be connected to the player identifier, so that no identifier has to be broadcasted with the protocol to know what player the message belongs to.
Of course all data would be validated server side, but that is a different subject.
Now, this seems pretty efficient to me, only 2 bytes to inform the server that I am moving forward and turning right.
However, most "professional" code snippets I saw seemed to be sending objects or xml commands. This seems to require a lot more server resources to me, doesn't it?
Is my unexperienced logic of why my text based protocol would be efficient flawed? Or what is the recommended protocol for real-time action multiplayer games?
I want to setup a protocol that is as efficient as possible, because I do not want to use multiple clusters/servers to cover excessive amounts of bandwidth for my 2D multiplayer game, and to safe synchronization problems and hassle.
However, most "professional" code
snippets I saw seemed to be sending
objects or xml commands. This seems to
require a lot more server resources to
me, doesn't it?
Is my unexperienced logic of why my
text based protocol would be efficient
flawed? Or what is the recommended
protocol for real-time action
multiplayer games?
Plain text is more expensive to send than a binary format containing the same information. For example, if you only send 1 byte, you can only send 10 different commands, digits 0 to 9. A binary format can send as many different commands as there are different values you can fit into a byte, ie. 256.
As such, although you are thinking of objects as being large, in actual fact they are almost always smaller than the plain text representation of that same object. Often they are as small as is possible without compression (and you can always add compression anyway).
The benefits of a plain text format are that they are easy to debug and understand. Unfortunately you lose those benefits if you put your own encoding in there (eg. reducing commands down to single digits instead of readable names). The downside is that the format is bigger, and that you have to write your own parser. XML formats eliminate the second problem, but they can't compete with a binary format for pure efficiency.
You are probably overthinking this issue at this stage, however. If you're only sending information about events such as the commands you mention above, bandwidth will not be a concern. It's broadcasting information about the game state that can get expensive - but even that can be mitigated by being careful who you send it to, and how frequently. I would recommend working with whatever format is easiest for now, as this will be the least of your problems. Just make sure that your code is always in a state where you can change the message writing and reading routines later if you need.
You need to be aware of the latency involved in sending your data. "Start turning"/"stop turning" will be less effective if the time between the receipt of those packets is different than the time between sending them.
I can't speak for all games, but when I've worked on this sort of code we'd send orientation and position information across the wire. That way the receiver could do smoothing and extrapolation (figure out where the object should be "now" based on data that I have that is already known to be old). Different games will want to send different data, but generally speaking you will need to figure out how to make the receiver's display of the data match the sender's, so you'll need to send data that is resilient in the face of networking problems.
Also, many games use UDP for this sort of data transfer instead of TCP. UDP is unreliable, so you may not get all of your packets. That means that "stop moving now" or "start moving now" may not be received in pairs. When coding on top of UDP then it's even more important to send "this is the state right now" every so often so that clients get ample opportunity to sync up.
The common way is to use a binary format, not text, not xml. So with only one byte you can represent one of 256 different commands.
Also use UDP and not TCP. The game will be a lot more responsive with UDP in case of packet loss. In case of packet loss you can still extrapolate the movements. With each packet send a packet number so that the server knows when the command was sent.
I highly recommend that you download the Quake source code where you can learn more about network programming in modern multiplayer games. It's really easy to read and understand.
edit:
I almost forgot..
Google's Protocol Buffers can be of great help when sending complex data structures.
I thought I would give my two cents and provide a practical application to what is being referred to as Binary Serialization. The concept is actually incredibly simple, yet only seems complicated on the outside.
You can actually send XMLs and have a server that processes the data within the XML to different functions within the server itself. You can also just send the server a single number that is stored within the server as a variable. After that, it can process the rest of the data and choose the correct course of actions.
As an example, some rough code:
private const MOVE_RIGHT:int = 0;
private const MOVE_LEFT:int = 1;
private const MOVE_UP:int = 2;
private const MOVE_DOWN:int = 3;
function processData(e:event.data)
{
switch (e)
{
case MOVE_RIGHT:
//move the clients player to the right
case MOVE_LEFT:
//move the clients player to the left
case MOVE_UP:
//move the clients player to the up
case MOVE_DOWN:
//move the clients player to the down
}
}
This would be a very simple example, and would need to be modified but as you can see you merely just store the variables encoded with whole numbers that you transmit in strings of numbers. You can parse these and create headers of information to organize them into different sections of data that needs to be transmitted.
Also, it is better to do a UDP setup for games because just missing a packet should NOT halter the gaming experience, but instead should be able to handle it client-side AND server-side.
What kind of newbie mistakes you've seen and what are the cures?
One which occurs again and again is client is not checked any way against server.
For example:
User decompiles flash game source or listens to network traffic and sees where high score data is going and sends bogus high scores there not even playing the game.
User uses trainer and gets item which may even not appear in current level. This sent to server like "client X got item Y" and server just accepts that.
The simple cure is of course handling gaming client only as API to the server. Then user can use trainers and other memory manipulations as much they like but server just says you can't do it. Think server as a database where you can query things with game rules on top of it.
For example
Client: starts game
Client: connects to server
Client: queries amount of available money from server
User: enables trainer which sets money to infinite
Client: server.buyItem('very expensive')
Server: Checks gamestate (user can buy things now). Checks player[0].money -> no bonus.
Client: server.buyItem('can get this')
Server: Checks gamestate (user can buy things now). Checks player[0].money, ok. player[0].items.add('can get this') which will reduce it's cost from player[0].money. Then inform client send(player[0], 'items', 'can get this'); send(player[0], 'money', player[0].money).
The other way is to record client's movements and send that to highscore server where server plays it. Of course this can lead to that that record is very big.
Without a doubt, blind trust of the client. In a game I'm working on, we now keep all "business logic" server-side, and have the client machines only send us what commands they are making; for instance "Player B wants to move right" - but the server calculates just how far to the right they moved. This has a performance overhead (and of course issues with lagging which could be handled better), so a possible middle-ground could be to do the heavy calculations client-side, and still have checks in place on the server; for instance checking whether the client's player is moving more than is supposedly possible in the time between updates; i.e. if the max player speed is 200 units/second, if you get an update after 0.5 seconds saying that they moved 150 units, boot them.
Of course, this doesn't necessarily stop someone from coding a bot to send those key presses, so there are other ways to guard against this. Still, having no validation at all is very much a newbie mistake (which admittedly I was guilty of when I took shortcuts)
The approach Valve took (at least, at one point) was to have the clients and the server simulate the game independently. Then the server does the authoritative simulation and sends status updates to all of the clients to correct their mistakes/hacking attempts.
E.g. if you press the left arrow your character will move left immediately; there is no wait for the server to say 'OK'. But if it turns out you've hacked yourself through a wall, the next server update will make you appear right next to wall, as the server sees it as solid.
Similarly, if a client sees a character move forwards, it will assume it is going to continue moving forwards until the server comes back with an authoritative response.
This approach defeats hacking attempts as the server makes the main decisions (and performs sanity checks in the process of simulation), and also deals with lag as the clients make predictions until they get word from the server.
Another big mistake related to 'trusting the client' is thinking your network protocol cannot be faked. People tend to assume that if they send binary chunks to the server, that these binary chunks will never be reverse-engineered, and that nobody will attempt to mess with the data to see what happens. This has led to all sorts of problems.
You guys have pretty much covered all that can go wrong with server trusting clients. There are no other real issues I can think of.
So instead of telling you what can go wrong, look at what can go right.
Valve has put a lot of work into their netcode. Read it up