Friday Facts #377 - New new rails

Posted by V453000 on 2023-09-22

Hello!
There are certain areas in Factorio that we haven't really had the courage to change for a long time. One of those areas has been the rail system...


The rail system needs change?

Whenever playing the game, we'd be reminded about two annoyances that are caused by technical limitations.

So called "S-bends" are not possible - two parallel rails would need at least 6 tiles in the perpendicular direction in order to connect.


How many times has it happened to you that two of your rails wouldn't be able to easily connect.

Signal positions are often very restrictive as soon as curved rails cross any other rail. So building junctions is a lot of trial and error to see if you can signal it properly.


How many times did you need to restructure an intersection because you couldn't place signals inside.

Apart from this, the code of the rail system accumulated some technical debt over time, like:

  • Hard-coded connectivity rules
  • Hard-coded rail planner logic
  • Curved rail being the only entity with multiple bounding boxes
  • Diagonal rails had front and back signal positions overlapping

Boskid was more than keen to rewrite large sections of the underlying rail code as one of the new benefits would be that we could easily define pretty much any rail shape. This was a prime opportunity to think really hard about solutions.

If we were to update the rail system, it would have to improve all of the major problems in a convincing way...

The S-bend

Adding an S-bend piece sounds like a very simple change - it would be just a special piece which would allow you to offset tracks by 2 tiles.


Let yourself dream for a moment, and enjoy the idea of how beautiful an S-bend like this would be.

But as always when it comes to Factorio, things are never simple...


All 5 of these directions would need to connect to a single rail piece.

At the moment, every rail can connect to at most 3 directions - left, straight and right. Adding a special rail piece would either make curves incompatible with s-bends - you could only build one, not both on the same spot - which would be a technical limitation, unobvious to the player why.

Or require two more connections (s-bend left, s-bend right) - which would mean that rail performance would suffer because of more options, and also that when you manually drive a train, arrow keys would not be enough to clearly decide where you want to go.

And it gets worse, because adding just a single s-bend special piece would not be enough. Offsetting rails by 2 tiles is nice, but maybe even more important is a 4 tile offset - which would be achievable by building two of the 2-tile offsets in a row, but that would be ... yeah, just, have a look:


I'm not entirely sure if this needs words, but I believe to a lot of us this is nightmare fuel delivered by pixels.

The idea

So we came to the conclusion that it might be ideal to split the curve in half, allow opposite curves to connect to each other - forming an S-bend and allowing signals to be placed in the middle. Plus, we would add half-diagonal directions to rails which could extend the S-bend as much as we want.


Half-diagonal rail between two half-curves - ANY length S-bend!

This idea is great and all, but how do we put it into tiles, rail shapes and actual graphics...

The geometry

All of the above sounds excellent on paper, but when it comes to the implementation, geometry is merciless.

There is one main rule that even the new rail implementation adheres to - every connection point has to be located on integer grid coordinates. This is necessary to make rail planner, and rail signal positions work reasonably simply.

The straight tracks are easy to make, but it's the curves which are difficult when we can only move the control points by entire tiles.

Cutting the curves in half would add control points in places which make it impossible to make the curve look nice. Have a look how jagged the new rail shape candidate curve would be:


This is in part because there are just too many control points. Since the diagonal triangles are both weird to build with in general, and pose a lot of geometrical difficulties, I was extremely happy to attempt to let them go.

Unfortunately, as you can see below, the middle of such a curve would end up in the center of a tile, which isn't an allowed position to define, so this won't work either.
You can also notice that while the curve is now much smoother in the middle, at the ends it's still a lot sharper than 1.1 rails were - which doesn't quite look like a natural circle either.


This means that we've kind of ran out of options to make a nice curve. Or at least - with this curve radius. But what if we try to make the curve bigger?

In fact just the smallest radius increment 11 to 13 tiles helps tremendously, the edge pieces are a section of a perfect circle, and the middle control point is on integer grid coordinates.


The final shape of rail curve we've settled on. It's nice and smooth and doesn't need any triangles or other straight sections in the middle.


New Factorio 2.0 rails

The curve size increase is minimal, but still not insignificant. However in practice it's surprisingly not so problematic. For example a T-junction footprint generally remained the same thanks to the additional signal positions.



Our toy trains are getting to choochoose from a whole lot of different rail pieces to run on.


The new curves and half-diagonals allow for much more nuanced shapes, so getting through narrow gaps is much easier.


Building 4 or 6 tile gaps between track directions is now even more interesting to decide between, with 2 tile gap now being possible at all.


There's enough candidate signal positions even when times get desperate.
You can also notice that the rail segment visualization has been changed, now it shows the signal directions.


In fact so many signal positions that junctions with 2 tiles in between are a possibility now, though if your Factorio friends have gotten used to 32x32 modular rail blueprints they might not tolerate this.


Speaking of which, the bigger curve radius means that with 4 tiles in between directions, now the minimal convenient blueprint module size is 32x32 tiles.
We have increased the big electric pole range to 32 to go along with this.


If you rework an entity, you better also rework its remnants. As a bonus they also have fuzzy edges so when rail remnants end they don't look as out of place as before.


What if I woke you up from your dream since the beginning of the post and told you this is reality?


Graphics process

The graphics of the new rails are something I'm particularly proud of. Reworking rails for visual improvement wasn't the goal and nobody was really complaining about the high resolution rails (FFF-163).

But can I just say I really, really like working on rail graphics, so I took this opportunity to make the rails look better than ever before.

The metal parts are thicker so they're visible more consistently even when zooming out, there is a bunch of fake shadows inside of the rails to make them generally look less flat, the layering of individual pieces is even trickier and more hideous than before, the ground integration just fits much better, and many more tiny improvements have been applied.

Of course, new issues which the old rails didn't have appeared, especially around combining the rail pieces together as every single rail can now just fork into 3 other rails. Meaning I for example spent literal weeks arranging the wooden ties bit by bit in a maddening process, but now the different rail pieces fit together really well.

And it wasn't just the rails, there was a following avalanche of things we needed to update to fit the new rails. Rail endings, train stops, all the remnants, rail segment visualization graphics, the graphics and the system for rail signal candidate spot visualization had to change, rail signals with so many new directions that even the circuit connector (the yellow box) needed new directions, and I'm probably still forgetting something.
I'm thankful beyond description to Jerzy from our 3D artists, who bravely handled the entirety of this avalanche so I could move on to other tasks, and retain at least some trace amount leftovers of sanity.

We were quite aware of the amount of things that would need changing. Some of it we've already done in the process of updating the rail graphics to high resolution in 2016, some of it were new features added over time like the rail signal / rail segment helper overlays.
Naturally, you would expect that since we already have systems for all of this graphics process, it'd be going faster than last time. The catch is, our quality standard also keeps increasing as we always find some things to improve, so this entire process still took several months to implement.

There were a lot of technical problems that boskid and kovarex had to handle. In particular making the rail planner behave even when it has many more rail pieces to choose from was quite difficult.

In the end I am truly convinced all of this was worth it and I believe you will feel the same way once you get to play with it.


Conclusion

The new rails are coming as a free update to Factorio 2.0 even without Space Age.

As you can probably guess, the new rail curves will be incompatible with the old ones. Savegames from 1.1 can be opened and trains will still run on previously built rails just like normal, but you won't be able to construct the old rails at all anymore.
In some future Factorio update when we decide to drop 1.1 savegame compatibility (Let's say 2.1), we will eventually get rid of the old rail shapes completely.

As always, we are thrilled to read and respond to the thoughts you express in the usual places.