Factorio - Klonan
Read this post on our website.

2020 Vision (Albert, Klonan)
2020 is going to be quite an exciting year for us. We have our 1.0 date set to the 25th of September, and there is a lot of preparation to do.

It is no doubt to any of us that we would not be able to have any success without the great community that has developed for the game over the last years, and the support of all our players and fans.

As is almost tradition, Albert has prepared a commemorative postcard/wallpaper to celebrate the last FFF of the year.



Here's to a great year to come!

The local maximum - The tutorials swap (kovarex)
I had few months of "vacation" from work by playing world of warcraft classic and generally getting some distance to be able to help with the finishing of Factorio with some perspective and a clear head. Now I have returned from the lands of Azeroth, back to work with fresh mind to finish what is needed - hopefully.

In this time, I was thinking about games in a bigger perspective. I have seen and admired videos related to game creation subject like A Love Letter to GOTHIC's Open World Design, Bethesda's game design is insulting, The decline of Gaming and the unbelievable story of the Fallout 76 fails that goes way further than I thought it can.

And then I played our new tutorial again and realized what we did. We found something very close to a local maximum. To start from the beginning: The whole goal of the new tutorial introduced in 0.17 was to explain Factorio to the wider audience. To make sure, that even someone who wouldn't normally play the game would understand the concept and would automate. The motivation was partially due to the fear of someone playing the tutorial who just doesn't automate on their own. That someone would miss the idea of the game and would had completely wrong perception about the game. For example, that someone would play it only for 30 minutes and would think it is just about endless grinding and manual crafting, and they would never experience the automation midgame which is where the game starts to shine.

This was a noble goal, but we didn't realize all the costs we had to pay for it.

To make sure that the players know how to research and use assembling machines, and they get to experience that part of the game fast enough, we had to force them to do it early on. Firstly, this breaks the progression, which is one of the cornerstones of Factorio game design. The progression in the beginning is roughly this:

Manual Mining -> Automated mining -> Automated logistics -> Automated production & science.

The order of the progression is very important, as in every step you start doing something new that you had to do manually before, so you appreciate the upgrade. Also, when you are starting, you are exploring the game mechanics in the logical order and understand the motivation for those. This is in clear contradiction with forcing players to use assembling machines in the first 5 minutes of the game.

Long story short, there was no way of just tweaking the new tutorials, the fundament on which it was built was wrong. Luckily, I wasn't the only one feeling that way. So I had to do the very hard thing, and telling the people that worked on it, that we are scrapping it, and in 0.18 we will switch to using the old tutorials again. They are way less polished with lower production value, but these things are much less important than the core gameplay mechanics as far as I can tell. We plan to tweak several things in the old tutorials, but the structure is planned to be kept the same.

This is definitely a lesson for the future.

Two million sales (Klonan)
It has long been on the horizon, and the Christmas gift giving has given us that last push, for us to reach 2,000,000 sales. I would say its quite an achievement for a Indie game that has never been on sale.

We first hit one million sales in May of 2017 (FFF-192), so its been about two and a half years to sell another 1,000,000 copies. I wonder how long till three million... Any bets?

I find it quite interesting (and not surprising) to look at the proportion of the sales that come from each of our distribution channels. As you can expect, Steam accounts for the majority of all copies of the game sold.



What is also interesting, is that we had a lot more sales on our site before we launched on Steam. Either this is Steam cannibalising our website sales, or just everybody who wanted to buy it on our site did so before launching on Steam. Another data point for speculating on, is that 81.3% of people who purchased the game on our website, redeemed and activated their Steam key. Factoring that into the above numbers, about 96.7% of all players own the game on Steam.

When we reached one million sales, we threw a party to celebrate. We're not going to do the same this with this milestone, but we are thinking of having a party to celebrate the 1.0 launch next year. Any news of that will of course be communicated in the usual way.

As always, let us know what you think on our forum.
Factorio - Klonan
Read this post on our website.

More particle optimisations (Allaizn)
Rseding's recent optimisations of the particle system (FFF-322) made particles much more lightweight thanthey were before, but it still left particles as rather complex beasts. A quick summary of the possible actions a particle can make during it's update:
  • Move their own position.
  • Advance their animation to another frame.
  • Land in water and apply a trigger.
  • Apply another trigger with a certain frequency.
  • Remove themselves from the game world once their life time ends.
What makes this complex is that triggers are general purpose systems that can do all kinds of things,including creating and destroying entities, fire, smoke and other particles as well as playing sounds or recursively applying even more triggers. In other words:applying a trigger is an "anything can happen" situation and thus totally unpredictable, which in turn makes optimisations extremely hard.

The particle emitter
The base game and most mods don't use particularly crazy triggers when creating particles - the goal is usually to just spawn in a bunch of small animated texturesand make them fly around on screen (which is somewhat ironically what is usually called "particle"). An idea for further optimisations of particles was hence to createa kind of "simple" particle, which couldn't apply all kinds of triggers to allow handling them in bulk, which is usually faster than handling them individually.This bulk handling would be done by a thing called a "particle emitter", whose whole job is to create, update, draw and finally destroy the simple particles it manages,with the idea being that a biter dying wouldn't have to spawn hundreds of particles, but only a single/few emitters.

But this is not all: simple particles are not able to change any other game state, and would thus only get updated to maintain their own internal values - mainly theirposition and velocity. A small physics exercise later the idea was born to not update the particles at all - you can compute their current position from their startingone after all! Even better: if the particles aren't ever rendered, then there's no point in creating them in the first place, so there's no reason to do that until theemitter comes into draw distance - millions of biters dying in gigantic blood fountains offscreen would thus basically not matter at all for your frame and update time!

https://cdn.factorio.com/assets/img/blog/fff-326-emitter.mp4

A visualisation of the emitter in action: the red box represents the actual screen.
Particles managed by emitters outside the screen region simply don't exist at all.


The particles themselves not being allowed to affect gamestate has another benefit: in a multiplayer game, each player only has to generate the particles theysee themselves, instead of those that are visible by anyone. This also suggests not using the emitter's update function, but it's draw one instead, which yields even morebenefits due to the draw function being called during the render prepare phase, which runs on as many threads as you allow it to have.

However, all of this doesn't just magically work correctly, and there are edge cases that need handling. For example: what happens if an emitter is created offscreen andthen comes into view distance? What happens if you save and reload? What happens if you save and reload with a mod set that doesn't have the particles defined any more? It would be very odd to see your rocket silo explode in uncountable bits, see how they fly and crash into the ground - then save and reload and see everything again because the particle effect restarted.

Handling these kinds of issues took some time and thankfully only increased the systems internal complexity marginally, allowing me to focus on expanding it's features.Currently, the following things are supported to be present on an emitter:
  • Handling simple particles with individual random starting positions and velocities.
  • Handling simple particle streams via normal and instant tails as shown in FFF-325.
  • Handling simple particles with a smoke trail behind them (FFF-325 has some examples of this, but the effect already existed beforehand).
  • Handling simple particles impacting the ground by potentially being replaced with a water splash when hitting water.
Particle emitters have two main restrictions:
  • They only handle a single particle type (and technically associated smoke and water splashes). Making an assembling machine burst into metallic blobs and oil splashes would thus require two emitters.
  • The particles managed by an emitter cannot fly too far away from the emitter (which itself will never move), because we need to know how far outside the draw distance to search for emitters that may want to render their particles.

https://cdn.factorio.com/assets/img/blog/fff-326-all-effects.mp4

A demo particle animation showing off all effects at once - all of these are managed by a single emitter.

Startup time - Data Cache (Rseding)
Game startup time (time to reach the main menu) is just as important to us as compile time (see FFF-206). With how frequently we compile and launch the game to test things, every extra bit of time spent waiting for the game to load is wasted time.

There are 2 main parts of the Factorio startup process:
  • Go over each enabled mod and collect the prototype data it defines/generates (the 'data stage').
  • Load and process the sprites that the game needs to run.

https://cdn.factorio.com/assets/img/blog/fff-326-mod-loading.mp4

This is a familiar sight to those who play with a lot of mods.

In the past we made an experimental setting which would cache the loading and processing of the sprites, so we never need to wait for it when nothing around them has changed. However, the game still had the process all of the 'data stage' every time the game would start.

During normal development that wasn't really an issue - it would happen in a fraction of a second in most cases. However, as the game has grown, so has the amount of stuff that gets processed during the data stage. Additionally, for every mod enabled that has anything in this stage, the time would roughly double. Recently I started to wonder what it would take to make the same kind of caching system we have for the sprite loading for the data stage.

Since mostly the results are the same between restarts, it would mean it didn't need to do most of the work - and should be faster. After working on it for about day I had a working prototype; but it wasn't actually any faster with just the base game. Not wanting to quit just yet I spent some time with the profiler and managed to find a few areas that I could optimize and reduced the time the caching logic was spending by about half. So, it finally had some benefit for the base game (although quite small).

What I didn't expect was just how much of an improvement it was going to have for the modded case. What used to take 25 seconds in my testing took only 4 with the new cache setting enabled. The time savings gets even better as the number of enabled mods increases. The setting is still disabled by default because it's highly experimental, but if it ends up stable enough, we might turn it on by default.

Christmas mods (Klonan)
This is the last FFF before Christmas, so I thought we would celebrate some of the mods which aim to create some holiday spirit in the game.
Alien biomes snowy terrain is just beautiful. In the map gen settings you can crank up the 'Cold Climates' option, so your whole world is just a cozy winter wonderland.


We must also remember to share the love to our biter friends, this mod will lets you deliver gifts far and wide, and embellishes the <strike>Artillery</strike> Gift delivery turret/wagon with a lovely red and green paint job.


And of course, no winter factory is complete without a lovely Christmas tree.



We wish you a merry Christmas, and as always, let us know what you think on our forum.
Factorio - Klonan
Read this post on our website.

Hello,
The year is wrapping up, and we have been hard at work finishing off some topics before we take our Christmas break. As you can imagine, releasing any new version of the game without a few weeks to do bugfixing wouldn't be wise, so you can rest easy this holiday period without the worry of a surprise 0.18 release.

New explosions and particles (Albert, Dom, Klonan)
One of the motivations behind the new optimized particle system (FFF-322) was to give our GFX team more flexibility to create special effects in the game, and specifically new explosions, without a major concern for any performance impact.

With the new system as the foundation, we have been working on adding new features into the trigger items and particle trigger effects. One such feature was to have particles spawn a 'tail' behind them. This tail looked good for some particles, but not really for others, so then we added an option to spread that tail out in a natural way. This 'Instant tail' gives the particle effect a more explosive feel, with the particles really bursting out dramatically from the source, rather than in a somewhat comical single-file stream.

https://cdn.factorio.com/assets/img/blog/fff-325-no-tail.mp4
https://cdn.factorio.com/assets/img/blog/fff-325-instant-tail.mp4
Instant tail off vs. Instant tail on.

Albert spent some time adding new specific explosions for the enemies dying. This is still a work-in-progress, but so far we are happy with the initial results.

https://cdn.factorio.com/assets/img/blog/fff-325-enemies.mp4

A nice feature we added back in 0.17 is the 'damaged_trigger_effect' on all entities. This lets each entity have a customised effect it creates whenever it is damaged. For instance with the biter, we made it create a blood particle hit effect, which gives the player some visual feedback about hurting the poor critter.

https://cdn.factorio.com/assets/img/blog/fff-325-biter.mp4

Another bit of refinement we can make is setting the effect to 'hit' at a random position inside a specified box. In the case of the Roboport, which is quite a big entity, the effect is very noticeable. We can make the random offset box any size and position we like, it isn't tied to any other property of the entity, so we can precisely tweak the effect.

https://cdn.factorio.com/assets/img/blog/fff-325-roboport.mp4

With these two in place, we can start to get a bit more specific. Dom has been hard at work the last few months creating specialized damaged effects with custom particles for every entity in the game. One example is the stone wall creating stone particles when damaged and when dying.

https://cdn.factorio.com/assets/img/blog/fff-325-walls.mp4

We can also mix and match the different particles, to better reflect the composition of the entity in the resulting rubble. For instance the rail has a mix of stone, metal rail, and wood particles.

https://cdn.factorio.com/assets/img/blog/fff-325-rails.mp4

These new effects and explosions are very much work-in-progress, and are already providing a much better feeling to the destruction in the game. Please let us know what you think, and if you have any suggestions to share. We are mindful of potential performance impacts a lot of particles could create (even with the new optimized system), so we are still looking into some even more performant ideas for the most brutal effects.

Steam review milestone (Klonan)
A Reddit post surprised us yesterday afternoon with the news that Factorio has reached 50,000 reviews on Steam (not including those who purchased the game from our website).



This is an absolutely huge number, and we never had any idea we would reach such a milestone when the game started as a small project just 7 years ago. Many thanks to all those who have reviewed the game.

In regards to other milestones... we might have something else to announce in the weeks to come :) .

As always, let us know what you think on our forum.
Factorio - Klonan
Read this post on our website,

Factorio logo patches (Jitka)
We would like to introduce our new fabric Factorio logo patches, which are now available at our e-shop. These sew-on embroidered patches are ideal for clothing, hats, backpacks, etc. The dimensions are 2.5 x 12 cm.



As we are uncertain how large the demand for these patches is going to be, we have only limited stock available at the moment.

Please note that our online store ships only once a week every Wednesday, and it is highly possible that the orders placed now will not be delivered before the 25th or December, this applies especially for orders shipped outside of Europe.

Sound design (Ian)
I have been brought on to Factorio to finish the sound for the game for version 1.0. It was felt that a sound designer was needed to work at the Prague office to help implement the sounds and improve the audio vision.

With a desire to make some quick wins, one of my first tasks was to add the sounds of the enemies footsteps, which we felt would really make them come alive. Unfortunately it transpired that the tech we wanted to use for this (each step being connected to the correct terrain, as per the player's footsteps), was going to be too expensive for the game in terms of CPU. After all, some of these creatures have 12 legs. Remembering a similar nightmare with giant spider's footsteps on a Harry Potter game years ago, I decided to make a simpler solution. So what we now do is to play a one shot sound for each cycle of the walk animation.

First of all I started sourcing sounds from a library so I could rapidly prototype something. By taking some eggshells crackling sounds and adding them to a video of the walk animations, I managed to create something pretty good for the biters steps or movements. I plan to record some extra sounds for these later on, but for now these work fine.

The sounds are different for each enemy however, the biters have more crackle and the spitters have more of a set of thuds. The bigger the enemy, the bigger the footsteps. These sounds should give you a greater feeling of immersion into their world, as you hear them scurrying towards you just before you see them.



Regarding the other enemy sounds, it seemed to me that the spitters and biters sounded too similar and this is something I wanted to change. If we can distinguish between the sounds made by the enemies, this adds to the variety and also the fun factor. The other sound designer Val has made new sounds for spitters idles, in order to bring out their squishiness and make them more disgusting. In the meantime I've been adding these sounds to the game, playtesting and tweaking them. For example, I chose better sounds for the enemies dying, in order to give clearer feedback to the player when making a kill.

In other news, I've been busy working on mixing the whole game and improving sounds as I see fit, but I'll leave that for another time!

Animated trees. Of course (Albert)
In last week's FFF we presented animated water as a mini-series of "small" additions on the feeling of the environment.
A lot of the feedback came saying that now the trees look pretty dead in comparison with water. We knew that in advance, and it seems like you were reading our minds because during the preparation of water we were working also on the trees. Today finally we can present this work finished.

The always running sound of wind in the game feels much better with these new animations, plus the sounds to come. The shadows cast by the trees are also animated, and it makes the effect on top of the water somehow much better.

https://cdn.factorio.com/assets/img/blog/fff-324-animated-trees.mp4

The idea of animating tree leaves is old as Factorio, but we never had the time due to obvious other priorities. One day Tom (wheybags) came with a very nice prototype, and I got very engaged -again- with the idea. Some time after, Ernestas made a new prototype based on different techniques. That was also really interesting. The subject was moving pretty solidly but it wasn't good enough. Next, Viktor (Allaizn), had the idea of using the normal maps of the trees instead of a generic noise to move the leafs, and the result of this experiment was fantastic.

The rest will be explained by Allaizn himself.

Tree shader integration - you probably forgot something if it works on the first try (Allaizn)
My first "big" task was to integrate the shader Ernestas made into the game engine, which was exciting due to its looks, but also somewhat stressful considering I only rarely looked at that part of the game's code until then. The first step in doing this is usually to understand how the shader itself works, so allow me to give you a small explanation of what is happening.

The GPU renders a texture pixel by pixel, and each pixel (roughly speaking) initially only knows where on the screen it is. A shader is then necessary to give it the extra information needed to arrive at the color it's ultimately supposed to have, where it acts a little bit like a "color by numbers" game - we ready a texture as the colors to use, and also pass in some numbers that tell it which part of the texture to use (their technical name is UV coordinates). When rendering sprites we almost always want to pass in these numbers in a way that results in the texture being copied onto the screen (see the image below) - but there is nothing preventing us from messing with those numbers beforehand ;) .


Left: you see the numbers that are chosen to result in an onscreen copy of the supplied texture.
Right: the scrambled result if you just supply random numbers.


Passing in random UV coordinates will usually result in an completely unrecognizable image, but we can be more crafty than that: we can pass the number passing to the pixel below the usual one, or to the one above - and if we do that strategically, the image looks like it shifted a bit. Vary this shifting in time, and the result is the appearance of slight movement across your image! This offsetting by a pixel or two is called distortion, and it's usually supplied to the shader by a second texture (whose color values we just reinterpret as the shifting values we need) called the "distortion map".

Back to to the implementation side of things, it was surprisingly easy to arrive at a working version since I could copy the hardest part (the shader itself) straight from Ernestas prototype - only to then realize that the title of this paragraph is almost always true! Trees can be drawn in surprisingly many ways:
  • High vs normal resolution textures.
  • No, high, or low quality compression.
  • Full or half color depth.
  • Leaves decrease in amount due to pollution damage and have a total of 4 stages.
  • Leaves desaturate with rising amounts of pollution.
  • Trees can be rendered as part of the game world, or as part of the GUI.
If you disregard counting the desaturation, there are thus 48 different ways to render the same tree sprite, and we of course want all of them to work, leading to me being stuck hunting for the missing cases for a few days.

During that time not everything went smoothly: sometimes everything seemed right with the code, but the trees seemed to refuse to move. There was thus always the question whether the effect was active at all, or if it was, then how much it actually did. This lead me to write a debug visualization into the shader:

https://cdn.factorio.com/assets/img/blog/fff-324-tree-debug.mp4

The three color channels encode the three main properties the shader has to work with:
  • The red channel reports the displacement in the horizontal direction - no red means displaced in one direction, full red in the other.
  • The green channel reports the same for the vertical displacement.
  • The blue channel reports how much the distortion has to be scaled by in order to account for different texture resolutions - full blue results in no scaling, half blue in a scaling of 0.5, no blue results in no distortion at all since it's scaled by 0.

The title theme also struck me in another way: the effect depends heavily on the provided distortion map, and our first version resulted in a look that was best described as "it looks fine if you turn it down until it's nearly invisible" - even the best implementation in the world just doesn't matter if the final effect doesn't look great, too. Given that the initial distortion map was mostly noise, I instead tried the very opposite approach: find a texture that is highly correlated with the tree leaf texture and use that instead - ultimately settling on the normal map of the tree leafs.

The shader itself uses only the red and green channels of the normal maps, which made them a fine target for BC5 compression that we haven't had use so far in the game (see FFF-281 for more info on compression). After an astonishingly short time, the compression was up and running - or so I thought, since I was once more struck by "did you think of this?". The culprit this time was mipmapping, which wasn't aware of the compression and thus downscaled the compressed image instead of decompressing, downscaling, and recompressing again.


Normal maps as seen in the sprite atlas

When the project was nearly done, I was hit one last time by the realization that I forgot something: moving tree leaves should result in their shadows moving too, right? I thus spent a little bit more time to implement a special shader for them that does just that by using generated noise instead of a distortion map.

Optimizations (Rseding)
There are a few key parts of the codebase that end up being "slow" relative to everything else and the reason why almost always simplifies down to edge cases.

"Why is ... so slow?" -> "Because it has to check for A, B, C and D each time it does any logic".
"Why? Those almost never happen" -> "Because without the checks, the logic is simply wrong".

About 3 years ago I had my version of this with inserters. Inserters end up being one of the more common entities for the simple fact of: you have to have them if you want anything to run. However, inserters are also one of these "slower" entities where the basic idea of what they do seems so simple; "how can moving items from A to B in an arc end up so slow?" (relative to everything else of course).

And so I looked at the profiling results and the code it pointed at:
  • Each tick; check if the inserter has a burner energy source. If it does:
    • Check if the energy source is completely empty and go to sleep if so (no fuel, can't move fuel into itself since it can never move).
    • Check if the item in the inserter hand can be used as fuel for this inserter. If it can:
    • Move the hand towards the inserter itself.
  • Each tick; check if the destination has moved away (teleported/vehicle drove away).
  • Each tick; check if the source has moved away (teleported/vehicle drove away).
  • Each tick; check if the target or source is marked for deconstruction.
  • Each tick; check if the source has changed force.
  • Each tick; check if the enabled condition exists and if the inserter is disabled by it.
If all of that passes, then move the hand towards the source/destination position.

It's not surprising that ends up being "slow". But you can't just not do any of that and say "it's okay". The obvious answer to all of that stuff is "that doesn't happen frequently/those are edge cases; they should all be done through events". But then - how? To put it simply; there was no event that the inserter could use to know when these things happen so it had to check each tick if any of them happened. I ended up leaving it alone and went back to working on other things. But it always stayed in the back of my mind; cooking - trying to find a solution. 3 years later I found it: Targeters.

Targeter driven events
Targeters are a thing we created and have refined over the years for 2 main reasons:
  • They're disappear-aware pointers; when the thing you "target" is deleted, your pointer is cleared (set to nullptr).
  • They're saveable/loadable pointers; you can persist a pointer through save -> quit -> load.
Most things in the game that need to "point" at something else will use these (with a few exceptions of course). Inserters use these. My idea was fairly simple: anything which can be "targeted" can go over anything "targeting" it and let it know when some rare event happens (everything the inserter had to check for and some others). The events aren't free - but because these cases don't happen commonly the inserter not having to do these checks makes the cost of the events when they do happen meaningless in the overall performance charts.

Snowballing
With the Inserter update logic drastically simplified and with the new Targeter driven events at my disposal I started to notice things:
  • Mining Drills share most of the same checks that Inserters do - so they got the same treatment.
  • Locomotives, Cargo Wagons, and Fluid Wagons had the same kind of checks; so now they don't need to be active in 99%+ cases.
  • The blue triangle module-requesters had the same kind of checks; so now they don't need to be active in 99%+ cases.
  • Logistic and Construction robots had the same kind of checks for (did the target move?) so now they don't need to check that.

After finishing with those I re-profiled and with those entities taking far less time different interesting things started showing up:
  • Burner energy source logic was doing several slow checks for the edge-case behavior.
  • Transport belts were doing a O(N) check every time they would move items when it could be done in O(1) time.
  • Anything which made smoke from consuming energy was doing several slow checks to try to make smoke when they didn't need to in most cases.
And finally one last thing showed up: heat pipes. Every time I make something run faster something else takes its place in the "what is time spent on each tick" (this is expected), but it also means it reveals new things I might not have noticed before.

Heat Pipes
The first thing I noticed with heat pipes is: all of the actual logic for heat pipe flow isn't even in the heat pipe entity itself. The entity just defer the logic to the "Heat Buffer" class. It got me wondering: why even have the "update" logic go through the entity at all if it doesn't do anything? Several days later and a lot more code than I set out to write; I moved all of the update logic for heat flow into its own dedicated manager class (almost identical to how fluids and electric flow have a manager class).

It looked too good to be true; what was 0.55 ms/tick was showing 0.17 ms/tick (a little over 3x faster) by just not going through the entity each tick to do heat flow. A lot of testing later and the results were correct; it was just that much faster. The underlying algorithm didn't change but it just ran > 3x faster now by touching less memory. This is another nice example of "Factorio is not CPU bound, it's memory latency bound". More cores wasn't going to make this faster - because it was never limited by how fast the CPU ran.

Conclusion
Electric networks... Fluid networks... Heat pipe networks... none of these interact with each other or anything outside of themselves. What happens if I just update all 3 in parallel? Not surprisingly; each of them got slightly slower (because they are competing for memory access) but overall it was still measurably faster. The interesting part about this though: 1 of the 3 always takes significantly longer to finish than the others. That means that the others end up being essentially "free"; the game has to wait for the slowest to be finished anyway so the faster 2 of the 3 get a "free ride" to finish long before game finishes waiting for the slowest to be done.

Every save file I've tested ended up running measurably faster in the end. The most extreme one (lots of steel furnace based smelting) showed a 2.3x speed-up.

As always, let us know what you think on our forum.
Factorio - Klonan
Read this post on our website

Water animation - Concept (Albert)
Since the very beginning of the project, we have focused a lot in the side of the factory, providing better designs for the machines, and expressive animations that give a sense of life and credibility in this area. We put a lot of effort also in the environmental side, adding different tile sizes, improving textures, adding doodads, cliffs, trees, decals, and constantly improving the map generation for a better feeling.

But apart from biters and the factory, nothing else moves in this Factorio planet. So the environment is nice looking but it feels somehow unreal due this lack of motion.

Today we proudly present the first experiment in this area: Animated water. This animation doesn't try to grab your attention, it's just there. Slowly moving. I personally bet that this animation, with the proper sound design, will provide the natural feeling that the planet needs.

https://cdn.factorio.com/assets/img/blog/fff-323-animated-water.mp4

Water animation - Technical Art (Ernestas)
Animation was always one of the most powerful creative tools we have. Animation is how we communicate with our audience about functionality, it creates interest and emotions people like. So let us talk about water and how the current representation might be missing something. Some of you with an eye for detail might have noticed that water in Factorio is static. It has foam, which is static. There are also some static reflections. Due to the fact that making animated water was considered polishing, we never took the time to make an actual solution.

But now we are polishing Factorio, trying to make it as beautiful as we possibly can given our constraints. I am glad to talk to you a bit about us solving animated water!

Christmas of 2018, I decided to gift myself with solving water animation in secret. Based on past conversations with Albert the goal for it was clear:
  • It had to look similar to the current water.
  • Photorealism was a no no.
  • It had to be super cheap for the GPU.
In the past I was experimenting with this cheap clouds shader. It used fractal Brownian Motion and only sampled a noise texture, instead of the usual approach of calculating Perlin noise. With a low iteration count, it was almost as cheap as drawing a sprite. So I started MonoGame (lovely framework) and implemented a tile-based world using the same technique for the shader, the only difference being I clamped noise values to simulate brighter and darker areas. For the noise I used our water sprite.


Original - Noise - Clamped

To save GPU power, water was drawn the same as tiles, one after another. The position was easy to solve also, I simply used UV coordinates to represent the game world position. With some trial and error, water was recreated with a moving effect.

https://cdn.factorio.com/assets/img/blog/fff-323-pitch.mp4

At the beginning of 2019, I pitched the prototype to the team. Sadly it was not really accepted mostly because of the movement. However, I sat down with Albert and talked and tweaked values to more appealing ones. After that, we basically forgot about it. Half a year passed and that solution was back on the table, I only had to solve reflections, foam, transparency, out of map transitions, and some other stuff.

Solving reflections, transparency and foam resulted in using a render target to save information for water shader. A render target is just a texture on which you can draw. Using three channels RGB, I am able to save three kinds of information. Red for reflections, green for transparency, and blue for foam. All drawing is additive to account for multiple tiles drawing on top of each other. This way we are able to add information not only for shore, but also for entities.

https://cdn.factorio.com/assets/img/blog/fff-323-layers.mp4

For out of map we updated our jelly feeling with waves on top. Basically we left the old graphics on the bottom and added animated water on top. For cutting/masking out water where we want, I used another shader that generated green waves in the water render target. Now some of you might ask why we did not use a waterfall. I mean it would look nice having a waterfall to this pitch-black hole of nothing. The reason is waterfall was the first thing we tried, and concluded that the jelly looks better and cleaner.

https://cdn.factorio.com/assets/img/blog/fff-323-out-of-map.mp4

Water animation - Game integration (posila)
For a long time, in order to make terrain rendering fast, we would keep an offscreen buffer with terrain that was rendered in the previous frame, and reuse it to render terrain in the current frame. If the players view didn’t change at all, we would use the offscreen buffer as is, if the player moved, we would shift the buffer accordingly, and render just the bits that were not visible before. Zooming or changing tiles in the view would invalidate the content of the offscreen buffer, and the terrain would have to be re-rendered for the entire view. But that happens only in a fraction of frames, so it’s not a big problem.

You may have noticed this optimization is incompatible with rendering animated tiles, so for the initial integration of Ernestas’ water effect, I had to force a full redraw every frame.

This created a performance issue, as the tile render prepare step would take up 3ms (almost 1/5 of total frame time) when zoomed out. Why does that matter?

The game’s main loop runs in 3 major stages:
  • Update - progresses the game state one tick forward.
  • Prepare render - collects the data that is needed to render the current view.
  • Render - uses this collected data to issue commands to the GPU.
While game update and render are executed in parallel, neither of them can run while prepare render does (more on this in FFF-70). So 3ms of additional prepare time means 3ms less can be spent in update before the update rate drops below 60 (and I don’t even want to mention how much time it would take in debug build, I’ll just say that I’d expect a lot of nasty looks from coworkers).

Luckily, I already had an idea how to solve this. The water animation depends only on global time, and the vertex data of water tiles doesn't change in between the frames, so instead of caching the finished terrain render in a texture, we can cache the data resulting from prepare render, which we call draw orders. To make it work, we cache draw orders per-chunk, and we only run prepare render on chunks that have just entered the player view (and weren’t in the cache already).

That pretty much solves the problem of the render prepare and has some nice side benefits. First of all, changing render scale doesn’t need to invalidate the new cache, so zooming doesn’t cause prepare render to run for all tiles in the entire view. Secondly, it creates opportunities for other future optimizations - for example, we can start caching tile draw orders that are likely to enter into the view in advance and spread this work over multiple ticks, or we can generate tile draw orders for each chunk in parallel as they are independent of each other now.

Even though the water effect is relatively cheap, some of our players play the game on really weak hardware, which already struggles with the current state of the game, so we needed to add an option to turn the effect off and essentially revert back to the old behavior. Initially I thought we would even use the old water sprites, but because we had to change the tile transition definitions, the old water would look really bad. I have decided to always render water using the new effect, but if you disable the animation, it will render frozen in time and will be cached to the offscreen buffer.

Since we were keeping the offscreen buffer logic around, we could utilize it for everyone if possible. I added a flag to cached per-chunk tile draw orders, that determines if the chunk contains a dynamic effect (and therefore needs to be rerendered each frame - if the animation is enabled) or if it can reuse pixels from the previous frame. This means when rendering chunks without any water (E.G, the middle of your factory), the new water effect will have no impact on performance.

Modding
When seeing this you might get excited about the possibilities for modding. Well, don’t just yet. The system has been setup for making it possible to define different tile effects, but at the moment it is limited to allow just 1, which is used to define the water effect. I plan to lift this restriction in the near future, but in the end you’ll be limited to only changing the properties of the effect we made. But that still might be interesting enough, due to ability to change the ‘noise texture’.

There is still no plan to support custom shader definitions before 1.0.

As always, let us know what you think on our forum.
Factorio - Klonan
Read this post on our website

Release plans (Klonan)
This week we released version 0.17.79, and marked it stable. Internally we have been calling this 'Stable 3', and the main feature was the new tooltips we showed in FFF-318.

There is one constraint we put on ourselves when we started this more swift feature release schedule: We want to avoid breaking mods. This is easy enough in principle, don't start renaming things, don't remove API features, etc. However as we develop further, there are certain features and improvements that we can't realistically do in a way that won't break mods, such as the new Character GUI (FFF-289) and color correction (FFF-320).

It is for this reason that we are going to accumulate some of these mod breaking changes, and release them all at once. Since it will definitely be breaking mods, we will bump the major version number, so it will be 0.18.0.

We have already internally started merging in these 0.18 features into our master branch, so we will not be doing any more 0.17 releases (unless something absolutely catastrophic is discovered).

The problem with particles (Klonan)
Particles have been in the game for as long as anyone can remember, and they are pretty simple all things considered. They are a small mostly decorative entity, that we use to add a bit of visual gratuity to the death and dying of bugs and machines.

For instance, Biters are full of blood, so when they die, they make quite a splash. Lets try to count how many particles we spawn in a typical dying explosion.

https://cdn.factorio.com/assets/img/blog/fff-322-biter-die.mp4
In this clip, the blood particle sprite has been replaced with a debug visualisation, to make counting easier

So it's quite a few. The Biter spawned 427 particles, and the Spawner 749. Well they don't persist very long, and they're only decorative, so it's all fine right?

One key word I would like to highlight in the previous description, is that they are an entity. When kovarex and slpwnd started making Factorio, they made a robust system for managing game objects and their interactions - the entity system - and everything that has a physical representation in the game world was built on top of this system. As the game grew bigger, it became obvious, the entity system is too heavy weight for some things, and we can get better performance by creating more specialized systems. This led to removing items on belts from the entity system in 0.12, and doing the same for smoke and terrain decoratives in later versions. Despite most other games or game engines having very efficient particle systems from the early stages of development, particles in Factorio are still piggybacking off the entity system in 0.17.

This means that particles are registered on the game surface in the same generic way as everything else. This also means, that they are iterated through when doing entity searches. So what sort of engine actions do entity searches?
  • Area trigger effects - such as grenade, flamethrower stream damage, atomic bomb, poison capsule.
  • Pathfinding - To check if a path can traverse a given tile.
  • Movement collision checks - such as Characters, Units, Projectiles.
  • And many others...

As you can imagine, having thousands of extra entities to iterate through every tick, can start slowing down the simulation. The worst case these days is defending your walls with flamethrowers. In the image below, all entities are highlighted with a debug visualization.



If you lost count, this scene contains 15,689 entities

Flamethrowers vs Biters are pretty much the perfect example of the problem:
  • The biters need to check every tick when they move if they collide with anything.
  • When the flamethrower streams land, they do splash damage, which is an area trigger effect.
  • The flamethrower stream also creates the fire on the ground, which does a collision check.
  • Every 10 ticks, the Fire on the ground do damage with an area trigger effect.
  • The flamethrowers kill biters very efficiently, so a lot of particles spawn in a very short amount of time.
This combination leads to some significant slowdowns later in the game when big groups come knocking. Also, since we improved the pathfinding, the problem is even worse in the latest versions of 0.17.

So how do we solve it?
Particle Optimization - Technical (Rseding)
When Posila first talked to me about doing a re-work of how Particles function in the game I had a lot of ideas. Not all of them worked out in the end but they sounded nice:
  • They wouldn't be entities.
  • They would work like smoke does (stored in contiguous blocks of memory).
  • They wouldn't need to be updated each tick if they didn't effect the game state.

In the end I found that it wasn't worth the added complexity to make #3 work.

The process
Particles needed to not be entities. Something being an entity has a lot of memory and performance overhead that particles just didn't need. Unfortunately when I implemented artillery I made the manual-targeting marker a particle. The reasons why don't matter any more, but it meant I had to add migrations to handle that and then migrations to handle removing all of the entity particles.

I stripped out all of the extra data/logic from particles that they no longer needed - reducing the size of each particle in memory from 224 bytes to 64 bytes. As a side effect of making them not entities it also reduces the amount of information that has to be saved in the save file. However, in most cases particles don't exist long enough to end up in the save file so that didn't really matter.

I needed some place to store/work with the particles runtime as they are created, exist for some short amount of time, and go away. Most stuff in the game ends up being stored on a given chunk (a 32x32 area of the world). In the case of particles I didn't care at all about any of the other stuff on a given chunk so I didn't want to stick them there. Instead, I made a separate thing that functions very closely to chunks and called it "particle chunk". The key differences being: they only exist when there are particles to update on them and the only data they hold are particles. That meant when the game needs to go over each particle to update them, all it has to do is go over all of the "particle chunks" that exist and run update. Additionally since I had full control of these new particle chunks I can recycle them in memory as needed to avoid spending extra time allocating and de-allocating memory as particles come and go.

The end result is a nice performance boost, reduced memory usage, and simplification of the logic around how particles work. A simple unscientific test we performed was nuking the same biter base in the old system and the new system, and recording what the max update tick time was.




The circular ring of entities around the edge are the 'Atomic bomb wave' projectiles.

Old system:
  • Max Entity update = 7ms.
  • Entity count (Excluding projectiles) = 7769

New system:
  • Max Entity update = 2.4ms.
  • Max Particle update = 1.7ms
  • Entity count (Excluding projectiles) = 786

This is not very scientific or highly controlled, but just to give an idea of the scale of the improvement. A 10x reduction in the number of created entities, and about a 40% reduction in max update time. Having the new optimized particle system also means the GFX team can go a bit more crazy with particle effects in the future...

As always, let us know what you think on our forum.
Factorio - wheybags
Bugfixes
  • Fixed that the infinity pipe mode could sometimes reset when changing other infinity pipe settings. more
  • Fixed that electric energy interfaces didn't consume power correctly. more
  • Fixed market GUI not showing price in the tooltips of modifiers. more
  • Fixed market GUI showing empty price property in the tooltips when no price is set.
  • Fixed lights render quality slider in graphics settings missing tooltip. more

You can get experimental releases by selecting the 'experimental' beta branch under Factorio's properties in Steam.
Factorio - wheybags
Bugfixes
  • Fixed a desync related to biter pathfinding. more
Factorio - Klonan
Read this post on our website.

1.0 date (kovarex)
Hello,
we feel that the Factorio development is taking way too long. The approach "It is done when it is done" was serving us well to deliver a high quality product, but if we continued this way, we would be doing it basically forever. A lot of us don't have any problem working on Factorio for some more time, but the main problem is, that we would like to introduce new features and content instead of just polishing parts that are already present in the game. We also considered, that the game is quite polished now, and if we just pushed the button to release 1.0, it wouldn't be a catastrophe. From our perspective, a lot of things wouldn't be finished, but from the perspective of a new player, the things we are working on now are mainly nitpicks.

With this in mind, we decided to just specify a 1.0 release date publicly, so we have to stick with it. We will just focus on the most important aspects as we approach the date, and we just do whatever we have time to do. Once the 1.0 happens, we can have some rest and after that, we can finally focus on the content and features again.

The date is 25th September 2020.

Version 1.0 does not mean that development on the game will end, or that Factorio is 100% finished. When we have a better idea of what we will be working on after the 1.0 release, we will let you know.

GDS 2019 (Klonan)
Game Developers Session 2019 is happening in a few weeks, Friday 29th and Saturday 30th of November. This year, like last, we are silver sponsors of the event, so you will see our banners around the venue if you attend.

This year we are happy to have two of our team doing talks at the conference:
  • Albert - "Developing the Visual Style of Factorio".
  • Vaclav - "Technical Side of Creating Factorio Graphics".
You can read a bit more about our talks and others on the speakers page.

Other than our two speakers, a lot of the team will be attending the conference, so if you see anybody sporting a Factorio t-shirt, it could be one of us (don't be afraid to come talk to us).

We also took the opportunity to do some updates to our cover art.



The Factorio team must grow (Klonan)
We have been on a bit of a hiring spree lately, trying to fill gaps in the team where we can identify them. We are happy to say, we have continued our team growth, with two new additions to the team.

Ian is a sound designer from the UK, who has moved to Prague quite recently. He will be working with us full-time here in the office, and with the help of Rseding for engine features, will be developing the soundscape of the game as we narrow in on the 1.0 release.

Next up is Allaizn. You might remember a few of our team mentioned him in past Friday Facts, and he is infamous for his experiments with cars on belts. He has had source access to the game for a long time, and in the past has made some good contributions through the program, so he has been able to get up to speed with us very quickly. For now he is reinforcing Posila in the Graphics backend department.

For some more details on our new colleagues and the rest of the team, we have short bios for everyone on our Team page.

As always, let us know what you think on our forum.
Factorio - wheybags
Changes
  • When a team loses in PvP, all their characters will die.
  • Technology GUI shows saved progress of partially-researched technologies.
Bugfixes
  • Fixed a crash when when loading modded saves that had construction robots working on modded entities.
  • Fixed that 'corpses' and 'dying_explosion' wouldn't be created on the correct force. more
  • Fixed that LuaEntity::get_fuel_inventory() didn't work on burner pumps. more
  • Fixed ammo turret tooltip not showing the damage bonus correctly. more
  • Fixed fluid name and amount not being shown when the tooltip is on the side. more
  • Show how module energy consumption is applied more clearly in the tooltips. more
  • Fixed several issues related to modded reactors set to use electric energy. more
  • Fixed spitters were not able to destroy trees and rocks. more
  • Fixed that shift+click recipes in cheat mode wasn't able to handle recipes that included fluids but still only produced 1 item result. more
  • Fixed a difference in map editor paused vs unpaused game ticking related to enabled/disabled train stops. more
  • Fixed that produce item per hour achievements could not be progressed. more
  • Fixed an issue with reading localised strings in Lua. more
  • Fixed that right clicking to add 1 item to assembling machines had no limit. more
  • Fixed that teleporting players/cars between surfaces would invalidate lua references to them.
  • Fixed a crash with trains that had wheels.direction_count = 0. more
  • Fixed statistics not counting items correctly on large intervals when a large number of items are produced/consumed. more
  • Fixed Beacon ghost tooltip missing some information. more
  • Fixed ghost tooltips not showing correct max energy consumption.
  • Fixed tooltips for tile creating items showing wrong title. more
  • Fixed blueprint strings not saving empty values for some circuit network settings. more
  • Fixed PvP config import would always append the default item and equipment lists. more
  • Fixed that creating infinity chests with logistic_mode set would ignore request filters. more
Scripting
  • Added LuaEntity::command, LuaEntity::distraction_command, LuaUnitGroup::command, and LuaUnitGroup::distraction_command reads.
  • Added LuaUnitGroup::is_script_driven read.
Modding
  • Changed RollingStockPrototype::wheels to be optional.
You can get experimental releases by selecting the 'experimental' beta branch under Factorio's properties in Steam.
...