Friday Facts #198 - Rail segment visualisation

Posted by kovarex on 2017-07-07, all posts

Hello,
after weeks and weeks of going through bug reports and fixing stuff (after all 0.15 was one of our biggest releases), it seems that we are approaching the end of 0.15 stabilisation. The (wishful) plan is to have a stable candidate for 0.15 next week. Sadly, this will change our attention to just different category of bugs: Those that we plan to fix for the 0.16 as they are not so critical and the changes required to fix them are too big to be done in 0.15 at this point.

Blueprint library trouble (Technical)

We had trouble with the blueprint library, mainly the blueprint duplication problems. Let me explain how it works internally. For performance reasons, the blueprint library generates and stores CRC of each blueprint. This can be used to quickly detect a duplicate blueprint when merging player blueprint libraries and blueprints stored in a save. For some reason, this wasn't working perfectly, as a lot of players were reporting that blueprints are somewhat being duplicated in the library. We assumed, that the error is in the CRC generation from the blueprint entities. That some property of an entity in the blueprint isn't initialized properly, so the CRC would be different for 2 blueprints that are the same. After some digging, we discovered what is wrong:

  CrcWriteStream* crcWriter = new CrcWriteStream();
  MapSerialiser mapSerialiser(crcWriter);
  this->save(mapSerialiser);
  this->crc = crcWriter->checksum();

The way it works is, that the blueprint is saved as it would be normally saved, but instead the data goes into a CRC engine. The problem is, that our MapSerialiser writes current output map version automatically in a constructor. This means, that whenever we changed version of factorio, which is every release at least, the CRC values of the blueprints changed, and they were suddenly considered to be different. It was quite hard to reproduce because of this. Anyway, forcing the serialiser to not write the map version to the output in this case fixed this issue.

We were also wondering how big is the chance, that 2 blueprints in one blueprint library will have the same CRC. The CRC is 32 bit, so there are 2^32 combinations. If we take into account 1 million players, and assume that each of them is having 20 blueprints in their library and all of the blueprints are random, the chance that it happens at least once is 9%. (You can try to calculate it yourself if you like math). Lets wait if it happens or not :)
Edit: It is actually 4.32736 ....%

Item stack optimisation (Technical)

One of our plans for 0.16 is the optimisation of the internal ItemStack representation. The current data representation of an item stack is like this.
struct ItemStack
{
  ItemCountType count;
  Item* item; // dynamically allocated classed based on the item type
};
The Item needs to be a pointer as different kind of items have different properties and can hold different kind of data:

This representation is nice and simple, but performance wise, it is bad, as whenever the ItemStack is accessed, it needs to access different part of memory to know the ID or any other information about the item as it is in the dynamically allocated part. When the item is transferred from one place to another, the dynamically allocated pointer can be transferred as well, but in cases when the stack needs to be split (which is happening almost always with stack inserter for example), a new copy of the dynamically allocated class Item needs to be created, which is generally slow as well.

To solve this, we can take into account the fact that vast majority of items in the factory are simple items (ore, plates etc.). We will simply just store the basic item data directly in the ItemStack, so it looks like this:

struct ItemStack
{
  ItemCountType count;
  ItemID id;
  Item* item; // null unless the item needs special data (blueprint, armor etc...)
};

Now, in the vast majority of cases, the ItemStack is simple and flat, so any operation with it will be much faster. It is possible that this change might improve the performance, but until we actually implement it and test it, we will never know.

Rail block visualisation

While testing our tutorial sample, which focuses mainly on rails and signals, people discovered that we have a debug visualisation called "show-rail-blocks", which looks like this when active:

The people were commenting, that once they used that, they were able to understand the way signals work almost instantly. The problem is, that debug options are generally not intended to be used in normal game, as the way these are generated is slowing the render a lot and the looks of it is far from production quality.
But it gave us an idea, that we should probably provide this visualisation in game properly. We are experimenting with the way it should look, but it might be something conceptually similar to this:

The first problem is, that using colors is very practical way to indicate which rails are connected into one segment, but it also makes the game look too much like a circus. We shall see what can we do if we use different than the RGB colors for it.
Another problem is the question, when exactly should it be shown, our first guess is to show it whenever building rails or rail signals, but the problem is, that the amount of indications you see when building rail signals is starting to be quite too high:
  • The new rail segment
  • Possible signal positions
  • Positions of train vehicles
  • Direction of the train that will approach the signal
  • Count of signals in the cursor
  • The cursor to be built
Which results in a bit of a messy composition:

So the final result is subject to our experiments, I just wanted to show you the process.

As always, let us know if you have any thoughts or feedback on our Forum.