Advertisement

Synchronization for simple game.

Started by May 15, 2017 09:33 PM
7 comments, last by hplus0603 7 years, 6 months ago

Hello world! I'm working on simple multiplayer game, clone of Flappy Bird for two players. I don't want to invent the wheel, instead i ask you to suggest me how to do players synchronization appropriately. I need to sync. two things, barriers spawn and bird actions. For barriers i have following idea : Generate blocks of barriers and index this blocks, for example server generate in advance 5 blocks of 3 barriers, send this info and start simulation, when some amount blocks go out screen, server generate new blocks and send this info to players. And about birds, when player tap screen he generate event with data ( bird position ) start simulation, and send this event to server, server accept this event, start it's own simulation and send this event to another player. Client-server architecture.

How can i manage this more accurately and properly? Thanks!

Why wouldn't you generate the full level from the beginning? The amount of data is trivial.

And, if your generation algorithm is well-defined (as in, you only use your own math, don't call system random or such) then all you need is to send the starting conditions for your level, and each client can generate the same barriers on their own, in the same order.

The main problem you'll have will be that of latency. On my screen, your bird will either be displayed behind me (even if we start at the same time,) or it will be displayed in a guessed/sometimes-wrong position. This is the unsolvable latency problem of the internet, and you have to design your gameplay to work well with this limitation.
Generally, displaying the other player behind seems like a fine option in this case, so that's what I would go with.
enum Bool { True, False, FileNotFound };
Advertisement
I can't generage full level because flappy bird is endless, but you are right, i can generate realy lardge piece of level because there is extremly low chance that players can pass at least 20 barriers. I thought about opportunity to generage level on client side, but eventually i choose randomized algorithm. I don't move birds, i move barriers, birds have static x position and only move up/down, i place first player behind second.

I thought about opportunity to generage level on client side, but eventually i choose randomized algorithm.
And hplus0603 is saying if you exchange the initial seed of the random generator between the clients, you can at both sides run the same algorithm (with the same random number generator and same initial seed), and get the same level without ever exchanging block positions.

i place first player behind second
That could work, except latency makes that up/down information arrives a bit later at the opposite side, so where a player makes a narrow escape, at the other side it may just hit a block.

Maybe the relative player position should take latency into account, but that may be complicated.

About client side level generation. If one of players minimize game on mobile device and after few seconds maximize it again we can, using inactive delta, restore actual state of barriers but there is potential issue that this player can out of sync with server eventually. There definitely need to be some synchronization mechanism for barriers.

Latency issues we can't eliminate completely, i understand that.
If you use all integer arithemetic, it is totally possible to generate a 100% deterministic level based on only a single seed value.
This is a technically solved problem. You do need to structure your gameplay and level generation code to be executable in this environment (and not accidentally use the systme random generator or rely on nondeterministic data, for example.)
If this is somehow not the right solution for you, then yes, it is totally possible for the server to generate the level "ahead" of the other players, and make sure that the clients have the data before they need to display it.
Given how finicky the mobile internets are, I'd make sure to generate, say, 10 seconds ahead of where the current player is.
enum Bool { True, False, FileNotFound };
Advertisement
Using same seed is a good idea, i agree. How this solution should like?
First i need to call srand( server_seed ); and then all subsequent calls of rand will produce the same result on all peers? But my game is multiplatform and i think because of different implementations of this function the result will not be the same on players hosts. How to properly solve this issue?


And i have another issue. I sync start game like that: each player send to server READY package, when server recieve this packet from both clients he start local simulation( barriers movement ) and send to both BEGIN package, after user recieve BEGIN package he start his own simulation. But here we have an issue, server simulation is on few seconds further of players simulation. And server can detect collision with barriers before player produce any actuons, while player can see that he didn't hit any barrier. How to sync start game properly? Any ideas?
But my game is multiplatform and i think because of different implementations of this function the result will not be the same on players hosts. How to properly solve this issue?

Include the random number generator in your own code.

But here we have an issue, server simulation is on few seconds further of players simulation. .... How to sync start game properly? Any ideas?

Inventing a delay-free and infinite bandwidth network would do the trick, but it is a bit impossible.

A second option is to synchronize time between the devices, so you can talk about time, and it means the same moment everywhere.

A third option is perhaps not to care. What goes wrong if players don't start at exactly the same moment?

First i need to call srand( server_seed );


System srand() is one of those sources of nondeterminism you cannot control yourself.
Implement your own pseudo-random generator, such as linear congruential (super simple,) XOR feedback register (slightly harder,) hash-based (also simple,) or even the Mersenne Twister (probably overkill.)
Then you can know that it always gives the same results everywhere, assuming everyone calls the same generator in the same order.

How to sync start game properly?


That's why I said you have to worry about latency.
Generally, the goal is not to make everything happen "at the same time" across the globe -- that concept ends up being meaningless in the presence of the speed of light (!)
Instead, the goal is to make sure everything happens "in the same order" across all participants.
This means you treat game simulation using well-defined simulation time (usually, 'tick numbers')

You still have the trade-off that you either have to wait for getting the inputs from everybody for tick T before you can simulate/show tick T (input latency)
OR you have to display other people "behind" the local player, and try to fix up any interactions that would disagree because of this
OR you have to try to forward-extrapolate other people on the local device, and try to fix up any interactions that would disagree because of this.

First i need to call srand( server_seed );


System srand() is one of those sources of nondeterminism you cannot control yourself.
Implement your own pseudo-random generator, such as linear congruential (super simple,) XOR feedback register (slightly harder,) hash-based (also simple,) or even the Mersenne Twister (probably overkill.)
Then you can know that it always gives the same results everywhere, assuming everyone calls the same generator in the same order.

How to sync start game properly?


That's why I said you have to worry about latency.
Generally, the goal is not to make everything happen "at the same time" across the globe -- that concept ends up being meaningless in the presence of the speed of light (!)
Instead, the goal is to make sure everything happens "in the same order" across all participants.
This means you treat game simulation using well-defined simulation time (usually, 'tick numbers')

You still have the trade-off that you either have to wait for getting the inputs from everybody for tick T before you can simulate/show tick T (input latency)
OR you have to display other people "behind" the local player, and try to fix up any interactions that would disagree because of this
OR you have to try to forward-extrapolate other people on the local device, and try to fix up any interactions that would disagree because of this.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement