Category Archives: Chronoclysm

Converting Chronoclysm to Online Multiplayer. It’s About Messages.

Games are information, a very specific type of information.

In traditional gameplay we don’t often think about how the information is relayed to the player. Players often don’t even realize that the information of the game is a meta idea that could be extracted from the activity they are doing.

For an example of this lets think about playing a game of chess. If you and your friend sat down to play a game across from each other you would only need one board and one set of chess pieces. You also wouldn’t need a method of communicating what state the board is in. With your friend right there they can simply look at the same information you are looking at and boom, both of you are looking at the same game state.

Now if you wanted to play chess with this same friend over a great distance we can appreciate the reality of the existence of the games meta information. Now there is still the challenge of playing a game of chess, but there is also the challenge of maintaining the game state for two separate boards and separate sets of pieces.

Moving a game from being local multiplayer to being online multiplayer is all about making that separation between the game state and game view.

The amount of information you send is very important. You could send for instance the position of every single chess piece each round. But that’s an exhausting amount of information and in a video game you are sending this information several dozen times a second. You need to only send important information. So don’t send the entire game state, just the changes.

The major difficulty with online multiplayer isn’t the actual networking of the computers together. Which is a tricky bit in its own right. It’s the abstract need to have the game rigidly defined enough to be encapsulated into messages. It’s hard to keep all of it organized.

Chronoclysm is a game about time paradoxes. Everything players do is recorded and played back. At first I thought this would be a really big boost to online networking, since I’m already logging every single action it couldn’t be that complicated right? Well it wasn’t as simple as I first thought.

A turn based game like chess obviously has several advantages when working with a messaging system. The biggest being the speed of the messages doesn’t completely determine the playability of the game. If it took 2 days to get you my move by mail we could still enjoy a long term chess game. Since the game is actually played in discreet steps.

The messaging complication in video games is better explained if we look at it like trying to turn soccer/football into a game played over distances. Where each player is miles away from each other, the information needs to be practically instantly sent to every player. Not just what each player is doing but done in such a way that the game actually stays in sync and all the information is updated enough to play smoothly.

That’s far more of a technical frustration. You need to structure the game so that it can be kept up to date. I’m a very large believer in code following the rules of physiology and biology. That is form follows function, your heart and lungs don’t conspire to push blood through your body. Due to their structure they can’t do anything else. The structure of the code should exist in such a way as to make message sending and receiving impossible to become unsynchronized.

Early on in Chronoclysm I ran into a bug because I didn’t do this when logging the actions. Since everything you do happens again I need to record all of the actions. When I first did it I made the process as follows: A character would go through the game and everything they did would be logged. So each time they hit a button or got hit by an object I played the action out and then recorded it.

That turned out to be a critical flaw in keeping the game synchronized in future rounds. It would never play out exact enough. There was constantly little things happening that were missed or the timing was poor. For a game that is about replaying the past over and over… it was a pretty big flaw.

The main problem was that the code itself wasn’t structured to ensure that things played out the same. There was a difference between recorded actions and live actions. The fix for this was simple. Instead of playing out the actions and then recording them to be played back later. I eliminated the first playing out of the actions. Instead all actions are logged as they happen and then played back instantly if they are new actions. This meant there was no longer two different ways for actions to happen, they happened the same if they were recorded or played back. You could spend your life trying to figure out why the actions didn’t play out the same, they should have as far as I could tell.

A rule of thumb is that the greater the number of parts, the more there is to go wrong. I eliminated the problem by reducing complexity, limiting the number of ways things played out.

Approaching online multiplayer is something very similar. You want to add structure to your game so that things communicate and stay in sync, because they can’t not.

We can start by figuring out what this sort of new structure looks like. First lets make the separation between game view and game state. Game view is what any one player see’s. Game state is what the actual game is. So one player could be playing chess with marble pieces and the other with wooden pieces. The pieces don’t need to look the same or be made of the same material, even though those are chess elements they aren’t important to the game state. The game state is purely the information that is critical to the game playing out the same way.

So the position on the board is important, but not the rotation of the piece on the board for instance. This is important to understand because we need to eliminate as much information as possible from the game state. The slimmer the messages the faster everything will go for the players.

Next we need to make it so that there is only 1 game state for all players. It’s a massive headache to try and synchronize game states across a network. It’s even harder if you are trying to agree on what actually happened. Think about a first person shooter where every single player is controlling the geometry locally. There is always lag across networks even if it’s small. One player might pull the trigger on their screen and register a hit. But due to lag the trigger pulling doesn’t register on the hit player until they have moved out of the way. There is now a discrepancy, did the hit happen? It technically did and didn’t, based on who’s game state you believe. A design that basically would guarantee desynchronization.

If we make it so that there is only 1 game state then it’s much simpler. This is often referred to as a client/server model. Where one central server provides information to the many clients.

It’s important to make a separation still between the game state on the server and the game view on the server. The server should not serve itself directly, it should have its own client. This again is for synchronization. If you have the server serving itself differently than the the clients there is more room for error. You are splitting something into more parts and that increases the entropy which increases the error rate. Of course a messaging system is more complex and also more prone to errors, but it’s absolutely necessary to online play so increase entropy as little as possible by making it as simple as possible.

This is where real world comparisons kind of start to fall by the wayside. Our game state should really only exist as an abstract concept. No physical form at all. It would be like having a game of chess where both boards and pieces existed. But the idea of the game being played was in a different dimension, the pieces layout has no form just information. You should have as many clients as there are players and the number of servers as there are games (one).

What needs to go into the game state and the game view is absolutely dependent on what the game is. If chess utilized the rotation of the pieces for instance it would be important to send that information, but it doesn’t so it isn’t. There is no rule for what is important, it’s contextual to the game state you are following.

Before even being able to send messages across a network you need to be able to break your game down into messages. I’m taking the approach of decoupling of the game state and game view. This means that things like collisions and the reaction to collisions don’t happen in line.

This would be pseudo example of tight coupling of the game state and view:

public void ExplodeBomb()
{
     Animation.SetBoolean(“Exploded”,true);
     Collisions[] effectedbyexplosion = PhysicsEngine.GetCollisionsInCircle(Position,Radius);
     for(int i = 0; i < effectedbyexplosion.Length;++i)
     {
         effectedbyexplosion[i].TakeDamage();
         if(effectedbyexplosion[i].Health <= 0f)
         {
             Destroy(effectedbyexplosion[i]);
         }
     }
}

At the same time we find the entities effected by the explosion we also tell them to take damage. Afterwards we check to see if their health is below 0 and destroy them.

So we have taken the concept of a bomb explosion and tied it directly with damage and character death. What happens if we have another type of explosion? Or how do we handle other types of damage? Maybe we just write the same code in those functions too, it would work. It’s just tightly coupled.

In the above code if we made that run on a network we would have to make sure each computer co-ordinated their explosion the same and hit the same objects. Also all at the same time. It’s an exercise in madness.

Instead we can decouple things. Do something like this pseudo code:

public void ExplodeBomb()
{
     Animation.SetBoolean(“Exploded”,true);
}

public void HandleBombCollision()
{
     Collisions[] effectedbyexplosion = PhysicsEngine.GetCollisionsInCircle(Position,Radius);
     for(int i = 0; i < effectedbyexplosion.Length;++i)
     {
         GameMessengerService.HandleCollision(effectedbyexplosion[i].id,this.id);
     }
}

//In the game object class
public void HandleCollision(int collidingid,CollsionTypes col)
{
    if(col == CollsionTypes.Explosion)
    {
        TakeDamage(6);
    }
}

public void TakeDamage(int amnt)
{
    Health -= amnt;
    if(Health <= 0)
    {
        GameMessengerService.HandleDestruction(id);
    }
}

public void HandleDestruction()
{
    Destroy(this);
}

While making it a lot more complicated we have also gone ahead and allowed there to be messengers in the process. So instead of having all the clients handle whether the bomb collided or not. Only the server decides if the collision actually happened. While we also make it so the animation is separate so that all of the clients can call it without affecting the game state. If one of the explosions on one of the clients lags they will just have a small visual issue. The game itself will retain its integrity.

Also inserted a message between damage and death. They are very similar but because a character might not die when they get damaged and there might be other reasons to deactivate a character. We will make them separate messages. So if the character dies we send out a message to destroy them. This was the clients all know when they died at the exact same time. Keeping congruence.

That’s the idea behind tight and loose coupling. Do you have two lego’s that come together to make one bigger structure? Or are your lego’s glued together so they are now one inseparable piece. Both have advantages. The glued one breaks less when you drop it, but good luck changing it in any way. To make a game work over a network you’ll need to break it up a lot more so everyone knows how to build the legos the same.

Of course it’s a fine line, if you break your legos down into atoms so you can mold them into any shape… well that’s certainly more decoupled. But you also are going to be spending an eternity just making 1 brick. It’s balancing the two that’s important.

The rest of converting Chronoclysm is going to involve going through the entire game and decoupling the game state and view. Which is the first step and it’s going fairly well thus far. I’m writing this because I think I finally have it mostly figured out. Once I have it decoupled I need to do the actual networking with sockets and stuff. Which is going to be a different bag of fun but shouldn’t be too hard since steam offers a lot of help.

Then there will be integration of a lobby system so that you can find people to play with. Which is similar to the other networking things but it’s a separate design challenge in its own right. I’m going to start dev logging more of this stuff, mostly because I find it absolutely fascinating and want to share.

I’m also available if you want to talk about converting your own project. I’m happy to offer any guidance or assistance. Happy gaming!
-Shane