Friday Facts #346 - He who does nothing, breaks nothing

Posted by posila, Klonan on 2020-05-08, all posts

He who does nothing, breaks nothing posila

In the recent patch notes, there was a line "Fixed landfill spawning under player when building landfill elsewhere. More" and some people on Reddit were wondering how did this bug happen in the first place, and asked for the long version and even suggested we could even use it for Friday Facts, and I thought: "Yeah, if I am going to spend time writing this, we should consider using it in FFF so someone else doesn't have to spend time writing something else." ... but I am going to stretch it out.


The landfill bug reported after the release of 0.18.21.

Disclaimer: I have not been around during the ancient parts of this story (speaking of which, it's my 5 year anniversary at Wube, yay!), and changes I have been around for, or even done myself, I might not remember correctly. So this might not be accurate. In fact, let's say the story is purely fictional and any resemblance to real world events and people is just a coincidence.

Tile transitions... again.

For the first couple of years of Factorio development, water drew a transition over ground tiles. The graphics for the transition tiles was taking too much space from the ground tile, so it was not possible to draw a single tile of ground surrounded by water... nor 1 tile wide tile bridge going through water. In addition to that, the transition graphics was tileable only with grass terrain. To enforce these constraints, the map generator was enhanced by tile correction step, the purpose of which was to make sure, that the terrain is possible to draw without any graphical artifacts. (If you wonder why the game didn't use Wang tiles instead, I know they were considered, but why they were not used I don't know. Based on the original water transitions it looks to me like things started with the intention to use them, but they ended up not working well with noise-based map generation. That's just my speculation though).

Of course, the tile correction was executed also when tiles were changed by means other than the map generator. From script for example. Mods that allowed players to place tiles emerged. One of them was Landfill, which was adopted into the base game eventually, and as far as I remember, the major trigger for that were reports from people who happened spawn on large island, and after 20 hours of playing the map, they found out they could not continue it. Adding landfill to the game solved those issues but created a new one. When placing landfill, the tile correction logic could decide to "correct" the tiles the player was standing on - trapping player in the water (bug report).


Bug report from 2016 - Placing landfill traps the player

As the team working on the game grew, it was decided to do another pass on the terrain graphics, put much more time into it, and change things around. As you probably already know (since we keep talking about it in past weeks), the ground draws shore transitions over water tile now, and shores are not limited to grass terrain any more. This made tile correction mostly obsolete, but it is still used to enforce some soft tile placement rules during map generation. For example that deep water should not be adjacent to ground tiles. Since we were leaving the logic in anyway, the possibility to define new tiles such that they would not be allowed in just 1 tile wide remained also.

Again, as you probably remember from 2 weeks ago, the new transition graphics and newly possible 1 tile wide creeks made it feel like player is getting stuck on invisible walls, or is unable to step over a really narrow gap in the ground. In addition, we already had the character slide a little bit around entity corners, and the new corner tile transitions that were visually diagonal, made me miss this behavior when colliding with tiles. So I started reworking how player character collided with tiles and how those collisions got resolved. What I found worked well, was to ignore the bounding box of the character and just test the terrain directly at player's position. If the tile type at that position is walkable, the player doesn't collide, if it is not walkable, we figure out shape of the transition on that tile and make the character to collide only on some parts of the tile. (note: this assumes walkable tiles draw transitions over non-walkable ones, in case you are thinking of creating a mod with new terrain type that player won't be able to walk on.)


Character movement when not considering tile transitions

My goal was to make player movement not be frustrating around water, and intended the rest of the collisions to work as they used to, despite for example enemies not being able to always chase after player. The map generator didn't create maps on which this would happen often, and I didn't mind players using landfill to create passages that could not be crossed by enemies. It just didn't seem to be worth further fuelling this chain reaction of solution to previous problem creating more new problem, because changing player collision was not without it's own issues either (have you noticed anything unusual about walls placed next to water? hint hint).

Anyhow, what I wanted to do, was to make a special collision function for the player character, but I soon learned, we have several collision functions for different situations, and I didn't want to make special version of each of them, so I decided to add a flag to character's collision mask, that would modify the collision detection method. Naturally, I wanted to make it possible for modders to change the collision mask of the character entity, so I exposed the flag to prototype definitions.

Mods ended up using the flag on non-character entities, and after Oxyd reworked the pathfinder, the flag started to cause crashes... Oxyd fixed it, but he changed my special logic to consider the entire bounding box again, instead of just the entity position, which made the feeling of player movement worse. This time I decided to solve it by adding optional parameter to the collision functions (instead of yet-another flag), that would indicate that the collision is being calculated for a player controllable entity, to determine if the old behavior should be used or not.

And that's how the bug was introduced. Remember that landfill bug with tile correction creating water under player? Well, the fix for that was to add a piece of code to the end of "build terrain" routine that would check the player who built the tiles is not colliding with water, and if they do, just place the ground underneath them to correct the result of tile correction. The special player collision logic allows characters to get so close to water tile that its bounding box collides with the water, and when I added the extra parameter to the collision functions, I didn't adjust this code, so it was using "consider the entire bounding box" collision behavior and falsely detected the character entity as colliding with the tiles and tried to save the character by placing ground under its feet.


Landfill bug

And here comes the revelation. The big confession. When the first post reporting this bug came in, I immediately knew what the problem was. It wasn't the first time I've seen it. The same issue happened to me when I was making the special player collision logic the first time around. Back than I caught it and fixed it even before the entire tile transition rework was merged to the main code base. But I didn't make a test. I did not... make a... test.

So that's how bug like that happens. The short version would have been something like... the bug was the result of long forgotten pieces of code, that are supposed to solve an edge case problems that were usually created by solutions to other edge case problems, interacting in an unintended way after changes that were made to solve yet another edge case problem.

In Czech we have a saying for which I have not found English equivalent. "He who does nothing, breaks nothing." It is a kind of reassurance when something unintentionally breaks during an activity, resulting in inconvenience. The only way to make it a certainty that nothing would have broke would have been to do nothing. At times the proverb sounds like an advice... if I can't figure out all the problems a new feature, change, or bug fix will cause, or just the number of potential issues that will need to be solve to do the change seems overwhelming, doing nothing starts to feel like an option with the best possible outcome. But, that's just analysis paralysis creeping in, and what I need to do is to remind myself the intended meaning of the proverb, and stop worrying about potential problems that may not even be real in the end, and if they are, they will be just inconveniences that will be eventually solved too.

Character and vehicle movement effects Klonan

This week we're happy to show the latest in visual effects that Dom has been working on. Carrying on the topic of improving the way the terrain and environment feels and reacts to the player, Dom and posila have spent quite some time working on movement effects for the character and vehicles.

As you walk around, on certain terrains, the character will kick up some dust and dirt.

The effect actually makes a really big difference to how it 'feels' to walk around, which the GIF might not show that well. Especially with some exoskeletons equipped, you really feel like your zooming around in a real place.

Walking around will also leave some subtle footprints in the ground, which helps connect the character to the terrain.

The vehicles also kick up the dust and dirt as you drive around. This feature actually is not as simple as it would first seem from the result, and there are quite a few new features under the hood to make it possible.

Discuss on our forums

Discuss on Reddit