Game channels allow fast game-play, without the need to wait for block confirmations between moves. The Xayaships tech demo shows that this works, but it is still a turn-based game. In this document, we want to describe how game channels can be applied to build games that “feel” truly real-time to the players.
In order to use game channels, the underlying game needs to be split into turns and moves that the players send each other. We conjectured already in the original game-channel paper that it may be possible to make this “invisible” to the players themselves by just having the game software send moves automatically in a quick succession, thus hiding the fact that there are moves at all from the frontend interface. With this, so the idea, it will be possible to have near real-time game play that works still fully decentralised and trustless, secured by the XAYA blockchain.
An interesting class of “real-time” games is based on some physics simulation that mimics continuous time, where the players can affect the state through sending commands at certain points in time. For instance, this class of games includes simple racing games, fighting games or even games similar to League of Legends. These games are what our discussion below is about. For simplicity, we also focus on two-player games, although the described approach works also for more players (or multiple players could form teams where the respective “team leaders” are trusted and thus in effect we have a “two-player” game from the backend’s point of view anyway). Let’s say Alice plays against Bob.
Since we are interested in multiplayer games, there will clearly be some latency between the players when relaying messages. Let’s assume that the single-path latency from one player to the other, including computations necessary to process any data in the game backend, is some fixed constant L. Also, since the latency is larger than zero, we have to assume that the game physics work in a way that moves made by a player at the time t only affect the game state with some delay at time t+D. Let us assume that the delay is larger than the round-trip latency, i.e. D>2L. With this assumption, it will turn out that we can make the game feel fully real-time to the player.
The basic idea for implementing this is quite simple: Both players simulate the game physics continuously by themselves, such that the player is presented with a smooth and real-time view of the evolution of the game state. Within that evolution, the players can press buttons or otherwise interact with the game to send commands at arbitrary points in time (but with the understanding that due to game rules, the commands will only take effect after the period D). Both players start their simulation around the same time, although of course in practice they will never get them started at the exact same instant.
Thus, there is a global time (corresponding to the time in the real world), and a game time for each player, corresponding to the point in time the player’s game simulation currently is; the game times for both players are typically not in sync, but will be close. For instance, it could be that at a certain point in global time, Alice’s game time is “4’242 ms after starting the game” while Bob’s game time is “4’123 ms after starting the game”.
Both players’ computers take turns for sending moves behind the scenes, using the game-channel framework. They do this at fixed points in game time. For instance, it might be Alice’s turn at 0ms, 200ms, 400ms and so on, and Bob’s turn at 100ms, 300ms, 500ms and so on. Let’s say a turn takes place every T of game time (e.g. 100ms in the example). When it is Alice’s turn, her computer automatically sends all moves she made (what command and at what point in game time) between her last turn and the current one, i.e. from the game-time interval (t-2T, t]. Bob’s computer does the same on his turns. (But these turns are not visible to the players themselves.)
This exchange of turns gives us a third concept of time: Alice’s sync time is the last game time for which she has received Bob’s moves, i.e. Bob’s last turn. As long as the sync time is not behind her game time by more than D, her game frontend can continue evolving the state forward in time, because Bob’s moves since the last sync time can not (yet) affect the state anyway. Thus, as long as Alice receives Bob’s moves more frequent than D, all works out and the game feels completely real-time! As long as L<T<D/2 (with sufficient safety margin) and none of the players deliberately tries to delay the game maliciously, this will work out.
For the game’s GSP and channel board rules, there is actually not much that needs to be considered specifically for real-time games. On that level, the game is simply turn based — Alice sends her game commands in an interval of length 2T and advances the game state by T, and then Bob does the same. The “magic” to make the game feel real-time to the user is handled by clever synchronising of times when the moves are sent in the frontend.
Basic Time Synchronisation
For the approach described above to work, we need to ensure that the sync times of both players do not fall behind their game times by too much (more than D). The frontend can try to keep times synchronised by following this recipe:
- Whenever a turn is received from the other player (for some time t), we update the sync time accordingly. Our next turn will have to be sent for game time t+T.
- If t+T is in the future of our game time, we just wait and evolve the game forward until our game time hits t+T. Then we send our next turn.
— In this case, the opponent will receive the move with a delay of L. So if their game time is off by at most L from our game time, then their sync time will be off by at most 2L<D.
- If t+T is behind our game time, then we will reply with the next turn (with commands up to game time t+T) immediately.
— In this case, we have a chance of “catching up” by T-L>0 through this action, thus ensuring that over time our sync time will catch up to the game time.
The flow of time and messages between the players could be depicted like this:
Here, in terms of global time, Bob’s game time relative to Alice is shifted into the global time future by the network and computation latency, L, because Alice sends the message to start the game to Bob and Bob only receives it with L latency delay. Thus Alice receives Bob’s turn for game time T at her game time T+L, and replies already at 2T with her next turn. Bob receives Alice’s turn at the expected game time 2T and thus waits a full turn length before sending his next turn at 3T. But due to Alice replying always a bit faster, the delay in game time between Alice and Bob can be kept constant and Alice will never run into a situation where the sync time lags behind her game time by more than D.
Even with the approach described above, we may need to explicitly synchronise times between the players. For instance, right when starting the game, but also perhaps after a transient network failure or (in the worst case) if one player is acting maliciously. In these cases, it could happen that Alice’s game time hits D in the future of the sync time. When that happens, her frontend has to stop the real-time simulation, because now actually the state evolution might depend on commands from Bob that Alice has not yet received.
The frontend could then simply pause the game until the next turn data from Bob is received and then continue immediately. But this may not be ideal, because Alice could stop paying attention to the game when paused, and could miss it resuming again; especially for fast-paced games this could be to her disadvantage. Thus, it would be better to trigger “explicit synchronisation” of times instead. For instance, when Bob has caught up, both frontends could display a countdown before the game resumes, so both players can be ready.
With this idea in mind, we could use this approach:
- When Alice’ game time hits a point where she can’t simulate any more, her frontend displays a screen “please wait”.
- When Bob’s turn is finally received, Alice adds a special flag “request time sync” to her next turn data that is sent to Bob. At this point in time, her frontend waits for whatever her game time is ahead of the current sync time (the game time of the turn data she sends), and then displays a countdown for a fixed amount of seconds (e.g. three).
— Let’s say, Alice receives Bob’s turn data at global time t, and that Bob’s turn data is for game time nT.
— In this case, Alice’s game time is at (n-2)T+D, because that is the point in time when Bob’s previous turn data stopped being sufficient for further simulation.
— Then, Alice waits for (n-2)T+D-(n+1)T=D-3T and then for the countdown of time C before continuing.
— Thus, after the countdown, Alice’s game time (n-2)T+D corresponds to global time t+D-3T+C, so that Alice’s game time is behind global time by t-(n+1)T+C.
- When Bob receives Alice’s sync request, his frontend immediately shows a countdown for C before continuing the game.
— The global time when Bob receives Alice’s sync request is t+L.
— His game time at that moment in time is nT+2L, because it took 2L for this last turn data to reach Alice and then for her immediate reply with the sync request to get back to him.
— After waiting in the countdown for C, the global time corresponding to this game time is t+L+C.
— Thus, Bob’s game time is behind global time by t-nT-L+C.
- Thus, after the synchronisation procedure, Bob’s game time will be ahead of Alice’s by D/2>T>T-L>0, which is close enough for smooth operation going forward.
Note that if Alice repeatedly runs into that limit because Bob’s moves are delayed, the countdown could be set to 10 seconds the next time, and Alice could file a dispute for the third time (together with an even longer countdown for restarting the game in case Bob resolves). Thus the game could be built in a way that ensures that none of the players gets overwhelmed when a (longish) delay happens and then the game suddenly starts again with a fast pace.
By Daniel Kraft
Want to know more about the benefits of blockchain for gaming?
Join the conversation:
Find out more about the Xaya platform and its components: