Factorio bug fix: the one who does nothing is wrong
A land creation bug reported after version 0.18.21 was released.
Note: I was not yet in the company when the action of the old parts of this story was unfolding (by the way, recently was my five-year anniversary in Wube, cheers!), And the details of the changes that I was a witness or even a participant could be remembered incorrectly. Therefore, the presentation of the story may be inaccurate. You can generally say that all this is a figment of fiction and any coincidence with real events and people is a simple coincidence.
Transitions between tiles... again
In the first couple of years of Factorio's development, water painted transition tiles around earth tiles. The graphics of transition tiles occupied too much space among the earth tiles, so it was impossible to draw a single earth tile surrounded by water, just like a bridge one tile wide passing through water. In addition, transition graphics combined only with grass tiles. To take these restrictions into account, the map generator was supplemented with a correction step, the purpose of which was to make it possible to draw the relief without graphic artifacts. (If you ask why the game didn’t use Van tiles, then I can’t answer this question, but I know that this possibility was considered. Based on what the initial transitional water tiles looked like, I can assume that they originally planned to use them, but in the end they didn’t work well with map generation based on noise. But these are just my assumptions.)
Of course, the tiles were also corrected in cases when the tiles were not changed in the map generator, for example, through a script. There were mods that allowed players to place tiles. One of these mods was Landfill, which was later transferred to the main game; as far as I remember, the main reason for this was the complaints of players who started the game on a large island and after 20 hours on the map found that they could not continue the game further. Adding the ability to create land solved these problems, but created a new one. When adding land, the tile correction logic could decide to “correct” the tiles on which the player stands, which is why he was trapped in water ( bug report ).
2016 bug report - when a land tile is located, the player falls into the trap
The game's development team gradually increased, and it was decided to perform another iteration of the relief graphics, invest more time in it and change the system. As you probably already know (because we recently talked about this in our blog), now the earth draws a transition in the form of a coast on the water, and coasts can already be not only grass. Because of this, the stage of tile correction has become practically useless, but it is still used to apply some soft rules for placing tiles during card generation. For example, the rule that the deep water should not be located next to the tiles of the earth.Since we still left this logic in the game, the probability of setting such new tiles that could not be one tile wide was preserved.
As already mentioned two weeks ago , new transition graphics and new streams with a possible width of one tile could lead to the fact that the player seemed to be stuck in invisible walls or could not step over a very narrow strip of water. In addition, the character was already slipping a little through the corners of the entities, and because of the new transitions of the corner tiles, which visually looked diagonal, I did not have enough of this behavior when colliding with tiles. Therefore, I began to rework the method of player character conflicts with tiles and resolving these conflicts. I found that it’s best to ignore the character’s bounding box and test the terrain right in the player’s position. If the type of tile in this position is passable for the character, then the player does not enter into collisions, and if he is impassable, then we determine the form of transition on this tile and force the character to perform a collision with only some parts of the tile. (Note: this implies that passable tiles draw transitions on top of impassable tiles; this is in case you are considering creating a mod with a new type of terrain that the player cannot walk on.)
Character movement excluding transitions between tiles
My goal was to make the character’s movement near the water natural, and the rest of the collisions work the same as before, despite the fact that, for example, enemies do not always have the ability to chase the player. The map generator did not create maps on which this often happens, and I was not opposed to the fact that the players used the ground filling to create passages on which the enemies could not move. It seemed to me that it makes no sense to supplement the chain reaction of solving the previous problem, creating a new problem, because the change in the player’s collisions also had their own problems (did they notice weirdness with the walls located next to the water?).
I wanted to create a special collision function for the player’s character, but I soon realized that we have several collision functions for different situations, and I don’t want to make special versions for each of them. Therefore, I decided to add a flag to the player’s collision mask that modifies the method of recognizing collisions. Naturally, I wanted the modders to be able to change the mask of collisions of the character’s essence, so I made the flag open for prototype definitions. [Note trans.: Prototypes are used in Factorio to indicate existing objects, entities and technologies in the game, as well as their properties.]
As a result, the modders began to use the flag for other entities, and after Oxyd reworked the path search algorithm, the flag began to cause crashes... Oxyd fixed the error, but changed my special logic so that it again took into account the entire bounding box, and not just the position essence, because of which the player’s movement deteriorated. This time I decided to fix the problem by adding an additional parameter to the collision function (instead of another flag), which would indicate that the collision is calculated for the player-controlled entity so that it can be determined whether to use the old behavior.
And so there was a bug. Remember the land filling bug when the tile correction created water under the player? So, to fix it, it was necessary to add a piece of code at the end of the "build terrain" procedure that would check that the player who built the tiles did not have any conflicts with the water. If they are, then you need to put ground under it in order to correct the result of the correction of tiles. The special logic of the player’s collisions allowed the characters to come so close to the water tile that their bounding box created a conflict with the water, and when I added an additional parameter to the collision functions, I did not fix this code.Therefore, he used the “take into account the entire bounding box” collision behavior and erroneously determined that the character’s essence collides with tiles. Trying to “save” the character, he placed earth under his feet.
Earth Fill Bug
And then I had to confess and repent. When the first post appeared with a bug report, I immediately realized what the problem was. This is not the first time I've seen him. The same problem arose when I first created a special logic of collisions. At that time, I caught it and fixed it before the entire redesigned system of transitions of tiles was combined with the main code base. But I did not test it. I have not... tested... her.
This is how such bugs appear. In a nutshell, the bug was the result of a long-forgotten piece of code that was supposed to solve problems with border cases that were usually created by solving other problems with border cases. After making another change to solve another problem with a borderline case, their interaction led to unexpected results.
In the Czech language there is a saying for which I could not find an analogue in English: "who does nothing, nothing will break." This is a kind of encouragement in the case when something accidentally goes wrong, causing difficulties. The only way to break nothing is to do nothing. Sometimes this saying sounds like advice... if you can’t understand all the problems that a new function will cause, change or fix a bug, or it is simply impossible to determine the number of potential problems that will arise when making changes, then this becomes unbearable, and the best option begins to seem doing nothing. But this is just a crept analysis paralysis - you just need to remember the true meaning of the saying and stop worrying about possible problems that may ultimately not arise. And if they arise, then these will be just difficulties that will also be resolved over time.