0
\$\begingroup\$

I'm considering building a multiplayer game having a central server handling the game and keep clients updated. I was checking various examples of ".io" games styles of implementation and seems pretty straight forward that the logic is on server and clients are mostly dummy.

Now the question that I have is .. how dummy should be the client? Where do you draw the line?

To give more context, I was thinking of building a platformer with 2 players on it, a few obstacles on the way etc.

What is clear for me is:

  • any input the characters receive needs to be sent to the server and updated the other client.
  • any map event logic will stay on the server and update clients when happening

What is not clear for me is:

  • where do you place basic physics? like keeping the character on the map
  • how about a simple movement like Jumping? should it be like a state sent to the server?
  • what about the whole map? should the server know the entire map?
  • what if I want to destroy one tile of the map?

I would appreciate your point of view or if you know some examples / links where I can find more info about these things.

Cheers!

\$\endgroup\$
2
\$\begingroup\$

What is clear for me is:

  • any input the characters receive needs to be sent to the server and updated the other client.
  • any map event logic will stay on the server and update clients when happening

That is the gist of it.


where do you place basic physics? like keeping the character on the map

Given that you have decided on a central server...

Physics happen on the server. If a player jumps, the server needs to compute the movement and notify all players so they can see the player jumping. That means that physics on the server is a must. Your server is your single source of truth for the state of the game, and thus everybody differs to the server to know what happens.

By the way, being the server the single source of truth is how you prevent cheating. For example, if the server were to let the players tell it that they have powers ups, that there is not a wall, or that they do not take damage, or whatever... well, you can imagine... somebody figures out how to modify or make a rogue client, that's it.

With that said, there is value is having physics on the client (in addition to having physics on the server). It is used so that he client can have feedback while it gets the update from the server. When that update comes, you can interpolate the state to the result from the server. Your game can, and should be able to work without this, however, it can improve player experience.


how about a simple movement like Jumping? should it be like a state sent to the server?

The playes uses the jump input (button, touch, whatever it is), and then the client notifies the server. If you are simulating on the client, the character can start moving right away using client side physics. In fact, in general, you want hide the latency in the animation. The server will get the notifications from all the clients, and each server cycle/tick/iteration, the server will send updates to every player.

The clients will not send state, they will send commands to the server.

For the server you have options... it can send updates (send just what changed), or whole states. For a small game, for only a handful of people, there is no much difference.


Of course sending just what changed will mean less bandwidth, which is good... the reason to send whole updates is that a client has fallen behind could benefit from getting the current state instead of working its way up through the updates. That is, at some point the backlog of updates is havier than the whole state.

Thus, the server will have to decide if it is sending updates or the whole state about each object to which players. The first rule is that if for a given object, if the log of what changed about it that you would have to send to a given player is more information than just sending the current state, you send the current state.


what about the whole map? should the server know the entire map?

Yes, of course. The server will know the whole state. The server needs to simulate physics there anyway. The server is the single source of truth about the world. While there are things that can be client side only (because only one player can see them, and they cannot affect other players), in general the server is aware of everything.

With that said, if the map is too large, it is worth considering not sending updates of the whole map to all the players. The players only need to receive updates about things that they can see, which means that you do not have to waste bandwidth in notifying the clients about stuff that is happening at the other side of the world.

That will be your second rule: if the server knows that a player cannot see an object, it does not send notifications about it to that player.

See, that is a way players can fall behind! If the player is not getting notifications about an object, when the player gets to a point it can see the object, it will need the state of it from the server. In fact, the client could offload from memory all the map it cannot see, in which case the server will have to send the whole state of any new area the player walks in.

We usually do not want to send a log of all that changed in an area the player was not seeing. Why? Not only because bandwidth, but because, we do not want the client playing everything that happened in fast forward. The player should only see the current state, thus the server should only send to the client the current state.


In case it is not evident, you do not need to send the sate of things that cannot change its state. Thus, if the whole map is pre-designed (not procedurally generated as you explore※), and small enough※※, the players can download it all before hand, and now the network code only needs special considerations about dynamic objects.

※: even if the map is procedurally generated, you could send everybody a seed that is used to generate at the start. Then again, if the players can destroy tiles, it means that tiles are dynamic, and thus the server will have to send their state. However, if the player were unable to destroy or modify tiles... well, the network code does not need special considerations about it.

※※: If the map is too big, then the special consideration is to break it into chuncks that can be downloaded on demand.


As you would know, to simulate physics it is a good idea to have a space aware structure where you can query nearby objects (so that you do not compute collision with everything, just what is nearby). It is the same structure that will tell you about what objects you need to send notifications to a client.

In fact, you could have the server stop simulating things that nobody can see, and in doing so, save CPU time.


what if I want to destroy one tile of the map?

The client send the command to the server. The server decides what happens.

In some situations the client could be aware that a tile cannot be destroyed, in which case it can save you a bit of bandwidth by not sending the command.

Now, the server will decide if the tile gets destroyed, and if there is a drop, if that action triggers something, or whatever, and notify each player – that can see the change – about it. If it weren't done like this, a player could – as far as they can tell – destroy the tile but other players won't see the tile being destroyed.


Of course, there is an alternative. If each player sends commands to the other players, they can simulate them. That is what you would do in a P2P game. However, you have decided to have a central server. Hybrid? Possible. Too complicated. If you are not using a library that handles networking that is designed for that, I suggest to not do it.

If you want to try your hand at doing such library, well, be my guest.


To sum it up, I'll give you a bonus case:

The player opens a chest

If you were to let the player decide what is the chest, cheat, cheat, cheat. Thus, the server decides what is in the chest. That means that the client has to ask the server.

However, you do not want to allow the client to randomly query what is in every chest without having to open them. That would be cheating too.

Thus, the client must only be able to send commands. It is Tell, Don't Ask. And the command is that it opens the chest.

Now, the server has to tell that client what happens (was it empty? did a monster jump up from inside of it? was it locked? did it contain apples?). Of course, the network will take a little while. You can put an animation of the player going for the chest to hide the few milliseconds the network could take.

The server also has to notify every other client that could see, that the chest is being open, and the client could play the animation of the other player opening it, with sound and all.

Oh, but, some players were to far, there is no need to send a notification to them. Instead, when they get to this area the server will tell them about the chest. However, do not send an update, the client should not be playing the animation of opening the chest... instead, the client should see how the chest ended up (already open, for example), so the server needs to send the state, not what changed.


You say you are making a platformer. However, were you doing a multiplayer shooter, the advice I would give you would have been the same. Nothing in my answer – before this paragraph – is predicated on the game being a platformer. Thus, I would like to encourage to look for how networking works for multiplayer games, regardless of whatever they are platformers or not.

We are also not talking about databases and persistence, that is beyond the scope of this question.

Now, being your game a platformer, you may be able to do some optimizations. For instance, if you are constraining your players to a single screen (I do not know if you do), then you know you only care about objects that are in that screen. That makes figuring out who to notify about what, much simpler. In fact, you won't have the case of a player entering an area where another player did something, if the players are together the whole time.

Addendum: if you want to do like the old games where stuff would reset (enemies respawn, etc.) as soon as they are off-screen. You can do that too. It would be simpler code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.