Posted by kovarex on 2019-06-14

You might have noticed that a lot of rail related stuff was broken during these past releases, and now it is working more or less fine again. The story behind it is not so trivial.

Rail signal logic

The rail signal logic for automated trains is quite straightforward:

As a train moves forward, it tries to reserve signals in front of it. If it can reserve a signal, the whole block guarded by the signal gets reserved for the train. If the train can't reserve the signal, as the block is reserved or occupied by different train(s), it stops in front of the signal and waits. Once the train passes a signal and enters a new block, it removes the reservation on the signal and block it had reserved. Once it exits the block, the block can be reserved and entered by other trains.

This looks nice and simple, nothing fundamentally wrong could happen with this logic right? Especially since we have it there for almost five years and it all just works right?

If the answer to this was "Yes", it would be quite a stupid buildup, so the answer is "No" :).

The counter example

So in this example, the train is approaching from the right. The problem is, that it reserves the block number 2 twice since there is a special rule, that a train can enter a reserved or occupied block as long as it is reserved by itself.

Since the train reserved the block 2 twice but removed both of the block reservations by entering it, the second reservation, which the train still counts on, isn't applied on the block 2, and the block is basically open for any other train to enter. This can lead to collisions and surprisingly also desyncs since we don't save block reservations, but deduce them from signal reservations while the game is being loaded.

The solution

Once the problem was identified, the solution was quite straightforward. I added support for block to be reserved multiple times, removing the reservation decreases the counter, and the block is freed only if all the reservations are removed.

But the real bugs and problems started after, because we now need to be extra sure that the block is reserved exactly the same amount of times as it is unreserved. The logic around this was far from rigid before as it just wasn't needed. Quite a few strict checks were added all over the place, to make sure that an internally incompatible state doesn't appear, since we don't really want to have to fix these "this block is closed forever" bugs where it would be close to impossible figure out how the game got into that state.

P.S. Since we can now use train stops as waypoints, not only blocks, but rail signals can be reserved more than once as well, as a train can plan path in a circle and reserve the same signal twice along the path.

The effect

You can see how the internal changes of rails bumped our crash report counts, but it will hopefully go back to normal soon.

Well, you can't make an omelette without breaking some eggs... but overall the trend continues toward stability.

As always, let us know what you think on our forum.