If you design a real-time online game, the very first issue you have to deal with is time architecture.
In this article we would discuss server-client relations and what contexts to think about when designing a real-time 2D online game context using theories discussed in this article.
If you have ever read articles about game client server synchronization they refer to this "Player Client and Host Server" as dumb client and smart server.
If you have ever played Werewolf game (A.K.A Mafia) the moderator or commonly refered to as host or god is the server, and players are clients. During night time god asks players their moves, at the start of day he tells players what has happen during night and player decide what to do in their mind.
The night phase is when clients send their data to server and start of day is when they receive the feedback of what happen from server and day time is when they render the game.
The game architecture which valve refers to at the start of their article, uses the same concept.
- Client sends input to server.
- Server validate and calculate result
- Server sends result to clients
- Clients render the context in graphics.
As valve mentioned it's dumb for client to not predict it's move.
Imagine you headshot a camper and wait for server response to see if he is dead or not.
That's how you should design a game context, a context which can predict the result unless something else happen.
Back to the warewolf game, it's impossible to play if you don't run the game context in your brain.
The same concept should apply for the client and server. Client and Server both run a game context inside themself, yet this context can be different in all of them at the sametime.
Let player 1 (P1) and player 2 (P2) be inside a topdown game with metrix of 10x10 tiles.
At same time:
- P1 starts at 0,0
- P2 starts at 10,10
- Server knows P1 starts at 0,0 and P2 ar 10,10
At first second P1 moves to 1,1 P2 to 9,9.
But because network latancy of P1 is 1 sec and P2 is 1.5 therefore after 1 second this will be the situation:
- P1: P1 at 1,1 : P2 at 10,10
- P2: P1 at 0,0 : P2 at 9,9
- Server: P1 at 1,1 : P2 at 10,10
And after 1.5 sec server state will be true for both:
- Server: P1 at 1,1 : P2 at 9,9 Because server has just received P2 command.
If this situation happens, the clients would always be in a desync situation. We would get back to this situation when we are implementing this.
If we assume a no cheat intention between two client we can implement a peer to peer connection. Without a server deciding what should happen.
So there would be a socket open on every client for receiving requests, making it a semi server, returning their state everytime a request comes in.
But if we trust clients then they might lie on request like if you can move one square per turn and in 1 sec you can't move from 0,0 to 5,5 yet client forge the returning response or even change ingame state.
To prevent that we need a sever as middle-man which runs the same game context inside too and validates your commands.
When we talk about real-time game the very first thing to keep in mind is network latancy.
This latancy depends on how urgent a data has to reach each client. Do you mind if in a chess game with 10 minute time, your opponent response reach you 10ms late? No
Also chess is a turn base game not a real-time game. Imagine if you summon a unit in a battlefield for defence but they actually spawn 1 minute late cause response didn't reach the server on time?
Or even worse you spawn the unit and predict it defend and after 1 minute server correct your command and you see everything has been destroyed!
Well fear not we design context for this kind of problems.
As a solution to that matter we have to bundle our commands with clock time. Clock synchronization is somehow an advanced concept, you can learn more about it in Distributed Operating Systems book by Tanenbaum.
Yet for implementing the minimum time synchronization system in game we disuss it here; briefly.
True synchronization is not possible even if you packets move at the speed of light, it is refered to as Einstein's Synchronization. We can use some techniques to make this synchronization bearable.
Δt, also known as delta time is a concept used for determining events happen between two different times.
Imagin in "Rocket Leauge" a user was in position 100,200 at t1 and 150,200 at t3. Using these times known as timestamps we can go forward and backward in t1 and t3 knowing the car speed we can determine where the car was in t2.
Assuming t1 < t2 < t3.
Knowing delta time concept, if client 1 ping is more than some calculated threshold like 2 seconds the game event reaches clients too late and they might experiance a jump.
In games like Counter Strike Source game server used to send positions and force them to position so you see a terrorist dash from a side to other side.
But in a game like Clash Royale after you experiance a lag you see the events sent afterwards and units moving faster to a position they are meant to be.
There are lots of ways to deal with lag. I briefly explain them but you can read more about it on Wikipedia.
When we want to handle lags we want to stop the butterfly effect.
Butterfly effect is driven from an example saying a tornado is caused by influenced of buttefly wing flaps.
I classify user events into two distinct classes:
Safe: small changes does not cause butterfly effect
Unsafe: small changes cause butterfly effect.
Like RPG game when they are socializing. Like in Runescape. You can see how Runescape handles lags.
They use an approach by validation.
- Client sends input to server like moving or a chat and do not update nor render the game context.
- Server receives the event and sends clients in area the update.
- Clients all update and render the command in their world.
This approach is naive approach to handling lag and can not be implemented in realtime games. This approach does not distinguish safe and unsafe commands from each other and treats every event the same.
Another approach is distinction of safe and unsafe events.
- Client sends the command to server and by the time starts to update and render its own context with safe commands issued.
- Server receives the command and their timestamps and update and render its own context then sends the clients the commands and their timestamps.
- Clients receive the commands and update and render accordingly.
This approach may defer between games, some may implement a rollback and fast forward approach to completely keep in sync but some may not.
So thats how we start thinking about game synchronization for online games, yet designing the main components for keep the game sync is harder than the game itself.
In this article I defined some problems:
- Butterfly Effect
- Cheat Prevention
- Delta Time
You have to check and see which parts you have to implement in game.
First you have to list the factors causing a butterfly effect in game.
Then you must check if you can trust client so you don't need cheat prevention and validation of commands.
And at last if you want almost true synchronization you have to use delta time and timestamp concept on every command sent from user.
The rest is up to you; but in next episodes I will write a simple 2D top view shooting game with bullets flying around so we have to keep track of all bullets flying and player position.